为什么这么多调用析构函数?取消引用会在堆栈上创建副本吗?

时间:2014-06-15 21:55:07

标签: c++ destructor dereference

它是一段复杂的代码,因此不为提供代码片段而道歉。在我的代码中,我在堆上创建一个对象,如下所示:

{
  State *s = new State();
  ...
  #pragma omp parallel for
  for(int i =0; i < n(blah); ++i) foo(s);
  ...
  delete s;
}  

s只创建一次,但多次传递给foo(s)

在功能foo我有

void foo(State *s) {
  State tmp = *s;     // Does this create a copy on the stack ?
  ....
}

我当然可以避免像这样创建tmp,我的动机完全是审美的(即每次都避免输入s->bla())。

关于缓存和别名有State tmp = *s的优缺点是什么?

我在使用g++-4.6 -pg进行分析时观察到的是,State的析构函数有多次调用,尽管在主要内容中我只创建了一次。

所以我的问题是:取消引用为State tmp = *s;在堆栈上创建副本并在每次作用域结束时调用析构函数。

我的预感是调用赋值运算符来在堆栈上创建对象的副本,然后将其销毁。如果是这样,可以通过

来避免这种情况
State &tmp = *s;

2 个答案:

答案 0 :(得分:3)

是的,就像你说的那样。我甚至不确定你有什么困惑。

每当您将variable声明为T variable;时,都会创建一个T的实例,其名称为variable

T *var不创建T的实例,而是声明“仅”一个指针,而T& var一个基本相同的引用,具有一点点不同的语义。 / p>

在您的情况下,必须创建T的实例。所以无论如何你都会在范围结束时得到一个析构函数调用。从这个角度来看,我会说,任务并不那么重要;只是它创建了副本,所以你需要确保正确编写析构函数。但是,无论何时声明类型T的变量(即不是引用,指针或任何花哨的东西),在范围结束时始终会生成清理代码(析构函数)的调用。变量。

您只需查看声明并了解tmp的类型即可告诉所有内容。

也许是一个重要的注释。为了安全起见,如果你切换到参考,你应该将tmp声明为const State &tmp = *s;。< / p>

以前在foo中...下的任何内容都会对tmp的状态进行任何更改,只会对*s的副本进行更改,因此*s是“安全”。现在,如果有任何事情触及tmp,您将在foo之外获得可见的更改。

答案 1 :(得分:1)

你的预感是正确的,函数foo中的赋值将分别创建该对象的副本,然后在移出函数范围时将其销毁。 选择有一个引用会确实避免副本,这与在这种情况下直接使用指针非常相似。