2011-09-30 52 views
4

复制elision方法的标准定义: 在C++计算机编程中,复制elision是指消除不必要的对象复制的编译器优化技术。 让我们考虑下面的代码复制elision方法

#include <cstdlib> 
#include <iostream> 
using namespace std; 
int n=0; 
struct C 
{ 
C (int) {} 
C(const C&) {++n;}  



     }; 
int main(int argc, char *argv[]) 
{ 
    C c1(42); 
    C c2=42; 




return n; 
} 

这条线“返回N”将返回0或1,这取决于复制是否被省略。

也考虑这个代码

#include <iostream> 

struct C { 
    C() {} 
    C(const C&) { std::cout << "Hello World!\n"; } 
}; 

void f() { 
    C c; 
    throw c; // copying the named object c into the exception object. 
}   // It is unclear whether this copy may be elided. 

int main() { 
    try { 
    f(); 
    } 
    catch(C c) { 
} 
} 

它说, //复制异常对象到临时在异常声明。 //此副本是否可能被取消也不清楚。 所以我的问题是实现这种优化方法有多么有用,如果有时结果是不确定的?一般来说它的使用频率如何?

+0

在第一个例子中甚至没有副本。对于第二个示例:http://stackoverflow.com/q/7401521/46642 –

+3

@ R.MartinhoFernandes:在这个问题的第二个例子(而不是你的链接问题)中,与NRVO发生的警告相同:从'如果编译器可以保证在构造对象'c'时抛出异常,那么只有在异常的内部存储器才能被删除。即使在那里,根据我的理解,用户所具有的问题是标准没有强制规定这种行为,这意味着您不能依赖复制构造函数的副作用 - 这是标准明确指出的 –

回答

8

重要的是,标准明确允许这一点,这意味着你不能假定复制构造函数的副作用将被执行,因为副本可能会被忽略。该标准要求执行复制构造函数具有复制构造函数语义,也就是说,具有在您的域中与原始对象在语义上等同的第二个对象的生成的全部目的。如果你的程序符合那个,那么优化不会影响程序。另一方面,这是唯一的情况,我可以认为这个标准允许来自同一个程序的不同可见结果取决于编译器的作用,但是你已经被告知你不应该在你的拷贝构造函数中有副作用(或者说,你不能依赖于执行拷贝的确切数量)。

至于是否值得,是的。在许多情况下,副本非常昂贵(我故意忽略C++ 11中的移动构造函数)。考虑一个返回vector<int>的函数,如果不复制副本,则需要另一个动态分配,复制所有向量内容,然后释放原始内存块,这三个操作都可能很昂贵。

或者,您可以强制用户更改其代码以创建一个空对象并通过引用传递它,但这会使代码难以阅读。