我需要在make_pair中使用ref才能返回引用吗?

6

给定这样一个对象:

struct Foo {
    string _mem;
    pair<bool, const string&> Func() { return make_pair(true, _mem); }
};

我实际上是在返回对 _mem 的引用吗?我的理解是,在 中,make_pair 会转发我的类型,从而允许我使用此返回来捕获它作为对象的 _mem 的引用。

这种行为似乎与我在 gcc 8 上看到的一致:http://ideone.com/adz17e 但是,当我尝试在 上运行时,它会出现段错误。如果我更改为返回 make_pair(true, ref(_mem)),它就可以工作了,但我并不认为需要这样做。这些行为中哪一个是正确的?

2个回答

7

我实际上没有返回对 _mem 的引用。 make_pair(true, _mem) 是一个 std::pair<bool, std::string>,是成员的副本。然后将其转换为返回类型中的 std::pair<bool,std :: string const&>,这意味着您正在返回对立即销毁的临时对象的引用。这是无条件的悬空引用。

请记住,C++是一种值语义语言。默认情况下没有任何内容是引用,您必须明确说明。

您有两种方法可以做到这一点。您可以标记您想要一个引用:

return std::make_pair(true, std::ref(_mem));

make_pair会解开std::reference_wrapper,因此这个表达式是一个std::pair<bool, std::string&>

或者,您可以直接明确:

return std::pair<bool, std::string const&>(true, _mem);

你可以更简洁地写成:

return {true, _mem};

4

这是未定义的行为。

自c++11起,make_pair被定义为:

template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );

在您的情况下,_mem 是Lvalue,因此 T2 推断为 string&,但是结果对的 V2 是从 std::decay(string&) 推导出来的。 std::decay 总是会丢弃引用。返回的pair在 second 成员中具有悬空引用。

我编辑了问题并添加了我的解决方法,但我不确定它是否与您的答案相符。我现在返回:make_pair(true, ref(_mem)),这似乎有效。那样也会衰减到只返回类型吗? - Jonathan Mee
1
@JonathanMee 在 reference_wrapper<string> 上使用 decay 可以得到 string&。你不需要使用 ref,只需在模板参数列表中显式地放置类型:pair<bool,const string&>(true,_mem)。这个 make_tuple(true,_mem)pair<bool,string>(true,_mem) 是一样的,所以 _mem 被复制到本地作用域中,这就是为什么你会得到悬空引用。 - rafix07

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接