在类中存储对对象的常量引用

Storing const reference to an object in class

本文关键字:常量 引用 对象 存储      更新时间:2023-10-16

这听起来像是一个基本问题,但我没有找到任何全面的答案,所以就在这里。请考虑以下代码片段:

struct A {
    const std::string& s;
    A(const std::string& s) : s(s) {}
};
int main() {
    A a("abc");
    std::cout << a.s << std::endl;
    return 0;
}

演示。

据我了解,这就是UB。字符串文本"abc"绑定到构造函数中的const std::string&,创建一个临时字符串对象。它也必然引用a.s,一旦a被构造出来,它就会被销毁。也就是说,常量引用不能链式延长寿命。晃来晃去的参考,轰隆隆。在这种特殊情况下,我在 ideone.com 上根本没有看到任何输出,但任何事情都可能发生(记住迅猛龙)。

好的,这个很清楚。但是,如果这实际上是我们的意图:我们想要存储对对象的常量引用呢?对现有的,而不是暂时的?这听起来像是一项非常自然的任务,但我只提出了一个(几乎)自然的解决方案。通过std::reference_wrapper而不是引用接受构造函数的参数:

    A(std::reference_wrapper<const std::string> r) : s(r) {}

由于std::reference_wrapper从临时中删除了构造函数:

reference_wrapper( T&& x ) = delete;

这就像预期的那样工作。但是,这并不十分优雅。我能想到的另一种方法是接受转发引用T&&并拒绝除带有 std::enable_if 的 const l 值字符串之外的所有内容。我认为这更不优雅。

还有其他方法吗?

UPD 另一个问题:这是std::reference_wrapper的合法用法,还是被认为太具体了?

我会说自然的解决方案是做reference_wrapper做的事情:防止临时施工:

struct A {
    const std::string& s;
    A(const std::string& s) : s(s) {}
    A(std::string&&) = delete;
};

您还应该记住,默认情况下,具有引用类型的数据成员会使类不可分配(甚至无法进行移动赋值),并且通常很难实现赋值运算符。应考虑存储指针而不是引用:

struct A {
    const std::string* s;
    A(const std::string& s) : s(&s) {}
    A(std::string&&) = delete;
};

Andrzej Krzemieński 在轻量级和方便的"显式"库中提供了一个非常简单的类lvalue_ref,它以明确的意图解决了这个问题:

struct Processor
{
  Big const& _big;
  explicit Processor(lvalue_ref<const Big> b) : _big(b) {}
};
const Big b {};
Processor p {b}; // ok
Processor q {Big{}}; // error (temporary)