在我的代码中,scoped_ptr指向一个堆栈变量 - 这是否延长了堆栈变量的生命周期?

时间:2011-09-06 12:43:33

标签: c++ pointers boost

我想知道以下代码是否格式正确

 if (  nChildLines == 0 ) 
 {
    nChildLines = 1;
    Tag tempTag = attachmentlines.tag();
    cfgChildLines = &tempTag;
 }

这里,tampTag是一些对象。 cfgChildLines是指向'if'块之外声明的对象的作用域指针。

现在我的问题是,当'if'块完成时,tempTag会被破坏吗?如果是这样,指向tempTag的'cfgChildLines'的使用是否有效超过if块的结尾?

3 个答案:

答案 0 :(得分:5)

重要的是要记住,在C ++中使用地址并不能保证该地址继续指向有效的保护。语言中没有引用计数(这就是为什么我们必须发明scoped_ptr / shared_ptr / etc)。

牢记这一点,我们可以根据您的情况详细了解:

tempTag是一个自动变量,在创建它的范围结束时被销毁。因此,您所使用的地址将指向堆栈中的某个位置,以指向此范围之外的已销毁对象。由于您已分配给scoped_ptr,并且scoped_ptr假定它可以通过删除从the documentation

删除对象
  

scoped_ptr类模板存储指向动态分配对象的指针

(强调我的)

所以你违反了scoped_ptr的界面,一旦scoped_ptr被删除你就会有一些未定义的行为。

 {
    nChildLines = 1;
    Tag tempTag = attachmentlines.tag();
    cfgChildLines = &tempTag;
 } // tempTag destroyed here


// LATER
} // scoped_ptr calls delete, undefined behavior possibly crash, 
  // possibly an occasional crash

如果您确实需要更大范围内的tempTag,那么只需在需要它的更大范围内声明它,并且不要使用scoped_ptr。

void Foo()
{
   Tag tempTag 

    {
        nChildLines = 1;
        tempTag = attachmentlines.tag();
    }
}

考虑它的另一种方法:当您创建动态分配的对象时,您将获得其生命周期的所有权。您手动创建并销毁该东西。因此,您可以将此所有权传递给另一个对象,例如可以为您管理的scoped_ptr。相反,在堆栈上创建的变量将被自动分配和释放 - 创建和销毁的权限完全由调用堆栈保存,您不能将这些权限赋予自己或其他人(即scoped_ptr)。您只能策略性地将这些变量放在一个正确范围变量的位置,以便基于堆栈的自动生命周期与您打算使用该事物的方式相对应。

答案 1 :(得分:2)

是的,因为tempTag对象在if结束时超出范围时会被销毁,所以在if之后,cfgChildLines会指向被摧毁的物体。

您可以使用new通过对现有代码的最少修改来解决此问题:

 if (  nChildLines == 0 ) 
 {
    nChildLines = 1;
    Tag* tempTag = new Tag(attachmentlines.tag());
    cfgChildLines = tempTag;
 }

然后在if之后,cfgChildLines指向有效的Tag,当它超出范围时会被销毁。

同样,Node指出,从不new未分配的内容上使用智能指针。在您的示例中,您将智能指针指向堆栈分配的对象,即使它具有更长的生命周期 - 也是无效的,因为当智能指针超出范围时,它将尝试delete分配的堆栈对象并导致未定义的行为。

答案 2 :(得分:0)

你问:

  

“是'cfgChildLines'的用法,它指向tempTag,在if块的末尾有效吗?”

不,当然没有效果。你有UB。停止这样做。


注意:SO主持人Bill the Lizard删除了我以前的答案,这个答案实际上是相同的,大概是因为他认为他知道的更好。

currently accepted "solution"不正确,这个答案是正确的。

使用Word修正地理位置(将“东北”更改为“西北”)以及修改技术内容的SO模式真的很烦人。