2012-05-24 312 views
3

我有一个关于这个语法有关初始化的问题。C++复制构造函数

http://en.wikipedia.org/wiki/Copy_constructor

X a = X(); 
// valid given X(const X& copy_from_me) but not valid given X(X& copy_from_me)    
// because the second wants a non-const X&    
// to create a, the compiler first creates a temporary by invoking the default constructor    
// of X, then uses the copy constructor to initialize a as a copy of that temporary.     
// However, for some compilers both the first and the second actually work. 

#include <iostream> 

class Foo 
{ 
public: 
    Foo() 
    { 
     std::cout << "Default Constructor called" << std::endl; 
    } 

    Foo(const Foo& other) 
    { 
     std::cout << "Copy constructor called" << std::endl; 
    } 

    Foo& operator=(const Foo& rhs) 
    { 
     std::cout << "Assignment operator called" << std::endl; 
    } 
}; 

int main() 
{ 
    Foo b = Foo(); //case 1:default 
    Foo c = Foo(a); //case 2: copy constructor 
} 

案例1引用:
一旦在拷贝构造函数改变从常量的参数非常量,从维基百科预期的情况下1将无法编译。但是,当使用正确的拷贝构造函数运行时,它只会调用默认的构造函数。为什么它不会调用复制构造函数?这是在编译时完成的优化吗?

案例2:
案例1的答案可能会为我回答案例2,但为什么这只会调用一次复制构造函数?

+0

“*这是在编译时完成的优化吗?*”它被称为[_copy elision_](http://en.wikipedia.org/wiki/Copy_elision) - 请仔细阅读。 : - ] – ildjarn

回答

4
Foo b = Foo(); 

此表单需要一个有效的匹配拷贝构造函数才能存在,但拷贝可能会被优化掉。它可能被优化掉的事实并不能放松构造函数存在的要求。

通过使您的副本构造函数采用非const引用,它不再匹配,因为Foo()生成一个临时的,并且临时项不能绑定到非const引用。当你创建参数const引用(或者删除你的副本c-tor并使用编译器生成的副本c-tor)时,它可以工作,因为临时对象可以绑定到const引用。

+0

如果c-ctor不存在,编译器就会生成一个,所以这不是真正的需求...... –

+2

@LuchianGrigore:如果编译器生成一个,那么它就存在。 –

+0

好吧,但这会使语句变得多余 - 除非您指定编译器生成的语句存在。 –

1

X()是一个临时的,因此您不能将它绑定到非const引用(虽然MSVS有一个允许它的扩展名)。

1)是的,这是一个编译器优化

2)非法的,因为a不存在。但原则上,是的,编译器优化。