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

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”绑定(bind)到构造函数中的const std::string&,创建一个临时字符串对象。它也绑定(bind)到引用a.s,并且一旦构建了a,它就会被销毁。也就是说,const reference不能链接生命周期延长。悬空引用,繁荣。在这种情况下,我在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值字符串之外的所有内容。我认为,这甚至没有那么优雅。

还有其他方法吗?

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

关于c++ - 在类中存储对对象的const引用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35770357/

10-09 17:12
查看更多