2013-07-03 137 views
5

我想不通,为什么在接下来的一段代码,定义副本constuctor不打印......C++拷贝构造函数怪异

#include <iostream> 
using namespace std; 
class B { 
    static int count; 
    int data; 
    int id; 

    void print(const char* p) 
    { 
     cout <<p <<", "<<id <<", " << data << endl; 
    } 

    public: 

    B(int d=0) 
    { 
     data=d; id=++count; print("B(int)"); 
    } 
    B(const B& a) 
    { 
     data=a.data; id=++count; print("B(cost B&)"); 
    } 
    ~B(){print("~B()");} 

    operator bool(){ return (bool)data;} 
    B operator+(int i){print("operator+"); return B(data+i);} 
}; 


int B::count=0; 

void main(){ 
    B b(42); 
    B x=b+2; 
    bool z=b+1; 

    getchar(); 
} 

我希望得到一份拷贝构造函数打印与B x=b+2,但它不不显示。 任何想法? 谢谢,


输出:

B(int), 1, 42 
operator+, 1, 42 
B(int), 2, 44 
operator+, 1, 42 
B(int), 3, 43 
~B(), 3, 43 

所以它的返回值优化?

+3

它可能被取消。 –

+0

你使用什么编译器?如果它支持C++ 11,则应该定义一个移动构造函数 - 请参阅规则五。 –

+3

见[复制省略](http://en.wikipedia.org/wiki/Copy_elision)。 – juanchopanza

回答

1

我很快就把它弹入GCC,并注意到了相同的行为。显然,编译器正在以它认为合适的方式改变代码的行为。

其中之一:赋值不等于复制构造函数。我想,因为它是用“=”,它正在寻找运营商=超载,没有找到它,然后选择使用其常规构造函数创建一个新的B对象,然后使用默认分配复制到这X。由于它是一个简单的类,因此这是有效的

我改变

B x=b+2; 

B x(b+2); 

试图迫使它使用拷贝构造函数。但是我有同样的行为。然后我看着操作+的返回类型,发现它返回一个B.(无参照,但它可以作为参考,只要它服从预C++ 11条引用的规则进行评估)。因此,编译器再次以与上述相同的方式生成代码,因此我们没有使用拷贝构造函数。

如果更改

B x(b+2); 

B x(b); 

编译器计算出的拷贝构造函数可以使用(又名它能够生成到B的引用)。

我的猜测是编译器生成因为运营商+的返回类型的代码。它可能与非常量引用仅在pre C++ 11中作为左值处理有关。如此以来,运营商+被调用,它不能创建一个const引用从中传递到拷贝构造函数(因为运营商+的结果是左值)。所以它使用常规构造函数以及自动生成的赋值运算符来完成您所请求的工作。

希望这会有所帮助。