将const引用存储在类中的对象中

时间:2016-03-03 11:01:04

标签: c++ c++11 pass-by-reference

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

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;
}

Demo

只要我明白,这就是UB。字符串文字“abc”绑定到构造函数中的const std::string&,创建一个临时字符串对象。它也必然引用a.s,并且一旦构造a就会被销毁。也就是说,const引用不能链延长寿命延长。晃来晃去参考,热潮。在这个特殊情况下,我在ideone.com上看不到任何输出,但任何事情都可能发生(记住velociraptors)。

好的,这个很清楚。但是,如果这实际上是我们的意图呢:我们想要存储对象的const引用?对现有的,不是暂时的?这听起来像是一项非常自然的任务,但我只想出一个(几乎)自然的解决方案。接受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-value字符串之外的所有内容。我认为这更不优雅。

还有其他方法吗?

UPD 另一个问题:这是std::reference_wrapper的合法用法,还是可能被认为过于具体?

2 个答案:

答案 0 :(得分:4)

我说自然解决方案是做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;
};

答案 1 :(得分:0)

AndrzejKrzemieński在轻巧方便的lvalue_ref库中提供了一个非常简单的类"explicit",该类可以明确地解决此问题:

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)