2012-08-24 29 views
0

下面的代码真的很危险吗? doSmth返回向量对象,应从contdoSmth)复制该对象,然后将其存储在函数test的范围内的堆栈中。因此,我相信它只会在从test返回后才会被删除。从函数返回的栈上的对象破坏

struct MyData 
{ 
    double m_i; 
}; 

std::vector<MyData> doSmth() 
{ 
    std::vector<MyData> cont(10); 
    return cont; 
} 

void test() 
{ 
    MyData& oneElement = doSmth()[0]; 
    std::cout << oneElement.m_i << std::endl; 
} 

然而Valgrind的持不同:

Invalid read of size 8 
<line 1 in test function oneElement> 
Address 0x101281db8 is 8 bytes inside a block of size 72 free'd 
std::vector<BlockInfo, std::allocator<BlockInfo> >::~vector() (stl_vector.h:314) 
<line 2 in test function> 

难道是我的逻辑或Valgrind的谎言有问题吗?

+0

为什么不只是'std :: vector v = doSmth(); MyData&oneElement = v [0];'? – betabandido

+0

下面是一个更直观的示例:http://ideone.com/pG1n0。正如你所看到的,在结束这个函数之前,一切都消失了。 – chris

+0

我在标准中找不到这个地方,所以我现在不是100%确定。我不明白为什么valgrind写道“无效的大小为8的读取” –

回答

4

返回值在完整表达式结束时被销毁,即函数test中的第一个分号。那时,oneElement成为一个悬而未决的参考。

可以通过将它绑定到const引用延长的返回值的寿命:

void test() 
{ 
    std::vector<MyData> const & r = doSmth(); 
    MyData const & oneElement = r[0]; 
    std::cout << oneElement.m_i << std::endl; 
} 

在上述情况下,返回值是在函数的末尾销毁。

+0

-1,因为答案是错误的。常量引用是**不用**临时初始化的,所以延长生命期的规则不适用。 –

+0

@JamesKanze不doSmth()返回一个临时? – s3rius

+0

是的。它在完整表达式的末尾被破坏。 –

2

该代码具有未定义的行为。 doSmth的返回值是一个 临时值,在完整表达式的末尾会被破坏。你在 上面调用operator[],它返回临时对 临时数据的引用。临时销毁后,参考 悬挂,任何使用它是未定义的行为。

Valgrind是抱怨的权利。