引用会导致内存泄漏吗?

5
考虑以下的C++代码。
struct foo { std::string value; }

inline foo bar() { return { "42" }; }

现在想象一下,我有一个函数,它以以下方式使用bar()。
std::string my_func()
{
    const auto &x = bar();
    return x.value;
}

这段代码会泄漏内存吗?因为my_func只是持有x的引用?还是当my_func终止后,x仍然可以被清理掉?

我知道这不是引用应该使用的方式。但我刚刚意识到这个编译通过了,想知道它的语义是什么。


3
这段话的意思是:“这个代码是否能够编译成功?难道你不需要使用‘const auto&’吗?” - Brian Bi
你说得对。我原来的代码中有 const auto&。 - Kai Mast
4个回答

7

但是我刚刚意识到这个代码可以编译通过。

所提供的代码不应该编译通过,因为试图将临时变量赋值给左值引用。

错误:无法从类型为“foo”的rvalue初始化非const引用类型“foo&”

如果你修正代码,通过

std::string my_func()
{
    const auto &x = bar();
    return x.value;
}

那么,如果使用const引用的话,就没问题了,因为const引用的生命周期延长到了临时对象的生命周期。

抱歉...我原来的代码中有const。 - Kai Mast

4

简短回答:不行。

更详细的解释:在这种情况下,编译器将确保引用的临时对象存在于当前作用域的末尾。bar()按值返回一个对象。它将被复制到一个临时的匿名对象中,然后引用将引用该临时对象。

还有其他类似的情况,标准对此有明确要求:绑定到引用的临时对象存在于达到当前作用域的末尾。


1
不,字符串被复制到返回值中。x引用的对象在函数结束后就超出了作用域。

2
这应该无法编译。 - Slava
它在我的gcc 5.2上编译通过了。那就是让我感到困惑的地方。 - Kai Mast
它编译并正常工作。除了在“struct foo { std::string value; }”之后需要一个分号。 - pewpew
@pewpew 对,它有一个 C++ 标准不支持的“特性”。 - Slava

1

这不是一个泄漏,你的引用只是指向被临时对象清理的内存。

访问 x 将导致未定义的行为。可能是访问冲突。


我在我的项目中已经使用了一条非常类似的代码行约一个月,没有任何问题。这就让我感到困惑。 - Kai Mast
@VicroeLiehr bar() 返回一个 foo 对象。由于引用是 const,因此将 x 引用绑定到从 bar() 返回的临时对象是完全可以的。然后将 x.value 复制到 my_func 的返回值中,在 my_func 结束时,绑定到 x 的临时对象被销毁。没有泄漏,也没有指向无法访问的内存。 - nos
@ViktorLiehr 我已经阅读了源代码和你的回答。你的回答与其他答案也不相符。请确保你正在查看帖子的更新代码,原始代码将无法编译。我还假设你知道对临时对象的const引用的行为方式。这就是为什么我想知道你声称访问x的哪一行代码会导致未定义行为。 - nos
@ViktorLiehr 抱歉,这不是 const 引用临时对象的工作方式。const 确实会改变事情。看起来你不会相信我的话,所以你应该阅读这个,这个,这个或者 C++ 标准中的 §12.2/5 章节。 - nos
@nos: 我读了你提到的文章。谢谢,伙计!我刚刚学到了一个常量引用的行为不同。这就带来了很大的变化! - Viktor Liehr
显示剩余8条评论

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