带有 ref 限定符的 getter 的最佳实践

Tim*_*Tim 7 c++ const-reference ref-qualifier

以下代码会导致未定义的行为:

class T
{
public:
    const std::string& get() const { return s_; }

private:
    std::string s_ { "test" };
}

void breaking()
{
    const auto& str = T{}.get();
    // do sth with "str" <-- UB
}
Run Code Online (Sandbox Code Playgroud)

(因为const&根据我的理解,生命周期延长不适用于此处)。

为了防止这种情况,一种解决方案可能是添加一个引用限定符get()以防止在 LValues 上调用它:

const std::string& get() const & { return s_; }
Run Code Online (Sandbox Code Playgroud)

但是,由于函数现在既是const又是&合格的,因此仍然可以调用get()RValues,因为它们可以分配给const&

const auto& t = T{};        // OK
const auto& s1 = t.get();   // OK
const auto& s2 = T{}.get(); // OK <-- BAD
Run Code Online (Sandbox Code Playgroud)

防止这种情况的唯一方法(据我所知)是重载get()一个&&不返回引用的-qualified 变体,或者重载= delete它:

const std::string& get() const &  { return s_; }

const std::string& get() const && = delete;       // Var. 1
      std::string  get() const && { return s_; }; // Var. 2
Run Code Online (Sandbox Code Playgroud)

但是,这意味着要实现正确返回(const)引用的 getter 函数,我总是必须提供 Var。1 或 2.,这相当于很多样板代码。

所以我的问题是:是否有更好/更简洁的方法来实现返回引用的 getter 函数,以便编译器可以识别/防止提到的 UB 案例?还是我对问题的理解存在根本性缺陷?

另外,到目前为止,我找不到一个例子,在不处理重载的情况下,添加&const成员函数会带来任何好处&&……也许任何人都可以提供一个,如果它存在的话?

(我在 MSVC 2019 v142 上使用 C++17,如果这有什么不同的话)

感谢你并致以真诚的问候

eer*_*ika 0

目前尚不清楚您正在使用哪些限制。如果这是一个选项,您可以摆脱 getter(s),并让生命周期扩展完成它的工作:

struct T
{
    std::string s_ { "test" };
};

const auto& str = T{}.s_; // OK; lifetime extended
Run Code Online (Sandbox Code Playgroud)

对于 getter,您可以选择 1. 提供重复的 getter,或者 2. 接受调用者必须小心,不要假设来自临时 getter 的引用仍然有效。如问题所示。


您可以保留私有访问权限,同时仍然可以通过使用共享所有权轻松进行生命周期管理:

class T
{
    std::shared_ptr<std::string> s = std::make_shared<std::string>("test");
public:
    // alternatively std::weak_ptr
    const std::shared_ptr<const std::string>
    get() const {
        return s;
    }
};
Run Code Online (Sandbox Code Playgroud)

但您必须考虑运行时成本是否值得这么轻松。