它是一段复杂的代码,因此不为提供代码片段而道歉。在我的代码中,我在堆上创建一个对象,如下所示:
{
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;
答案 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
中的赋值将分别创建该对象的副本,然后在移出函数范围时将其销毁。
选择有一个引用会确实避免副本,这与在这种情况下直接使用指针非常相似。