根据Herb Sutter的文章http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/,以下代码是正确的:
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> f() { return {{1},{2},{3},{4},{5}}; }
int main()
{
const auto& v = f();
cout << v[3][0] << endl;
}
即。 v
的生命周期延长到v
const引用的生命周期。
事实上,根据valgrind,这可以很好地与gcc和clang编译并且没有泄漏。
然而,当我如此改变main
功能时:
int main()
{
const auto& v = f()[3];
cout << v[0] << endl;
}
它仍然可以编译但是valgrind警告我函数的第二行无效读取,因为第一行中的内存是空闲的。
这是符合标准的行为还是g ++(4.7.2)和clang(3.5.0-1~exp1)中的错误?
如果它符合标准,对我来说似乎很奇怪......哦,好吧。
答案 0 :(得分:11)
除了您的代码外,此处没有任何错误。
第一个示例有效,因为当您将f()
的结果绑定到v
时,可以延长该结果的生命周期。
在第二个示例中,您不会将f()
的结果绑定到任何内容,因此其生命周期不扩展。绑定到它的子对象将计算:
[C++11: 12.2/5]:
第二个上下文是引用绑定到临时的。引用绑定的临时值或引用绑定到的子对象的完整对象的临时值在引用的生存期内持续存在除外: [..]
...但是您没有这样做:您已经绑定到对象上调用成员函数(例如operator[]
)的结果,并且该结果不是该对象的数据成员矢量!
(值得注意的是,如果你有std::array
而不是std::vector
,那么the code †绝对没问题,因为数组数据存储在本地,所以元素是子对象。)
因此,您对f()
原始结果的逻辑元素有一个悬空引用,该结果早已超出范围。
†对于可怕的初始化器很抱歉,但是,责备C ++。