我编写了以下程序来测试何时调用复制构造函数以及何时调用赋值运算符:
#include
class Test
{
public:
Test() :
iItem (0)
{
std::cout << "This is the default ctor" << std::endl;
}
Test (const Test& t) :
iItem (t.iItem)
{
std::cout << "This is the copy ctor" << std::endl;
}
~Test()
{
std::cout << "This is the dtor" << std::endl;
}
const Test& operator=(const Test& t)
{
iItem = t.iItem;
std::cout << "This is the assignment operator" << std::endl;
return *this;
}
private:
int iItem;
};
int main()
{
{
Test t1;
Test t2 = t1;
}
{
Test t1;
Test t2 (t1);
}
{
Test t1;
Test t2;
t2 = t1;
}
}
这导致以下输出(只是添加了empy行以使其更容易理解):
doronw@DW01:~$ ./test This is the default ctor This is the copy ctor This is the dtor This is the dtor This is the default ctor This is the copy ctor This is the dtor This is the dtor This is the default ctor This is the default ctor This is the assignment operator This is the dtor This is the dtor
第二组和第三组的行为符合预期,但在第一组中,即使使用赋值运算符,也会调用复制构造函数。
这种行为是C ++标准的一部分还是只是一个聪明的编译器优化(我使用的是gcc 4.4.1)
答案 0 :(得分:10)
在第一个测试用例中没有使用赋值运算符。它只使用称为“复制初始化”的初始化表单。初始化对象时,复制初始化不考虑显式构造函数。
struct A {
A();
// explicit copy constructor
explicit A(A const&);
// explicit constructor
explicit A(int);
// non-explicit "converting" constructor
A(char const*c);
};
A a;
A b = a; // fail
A b1(a); // succeeds, "direct initialization"
A c = 1; // fail, no converting constructor found
A d(1); // succeeds
A e = "hello"; // succeeds, converting constructor used
复制初始化用于那些与隐式转换相对应的情况,其中一个未明确启动转换,如在函数参数传递中,并从函数返回。
答案 1 :(得分:3)
C ++标准8.5 / 12
发生的初始化 参数传递,函数返回, 抛出异常(15.1),处理 例外(15.3),和 大括号括起初始化列表 (8.5.1)称为复制初始化 并且相当于表格
T x = a;
新的初始化 表达式(5.3.4),static_cast 表达式(5.2.9),功能性 符号类型转换(5.2.3),和 基础和成员初始化器(12.6.2) 被称为直接初始化,是 相当于表格
T x(a);
答案 2 :(得分:2)
您的第一套是根据C ++标准,而不是由于一些优化。
C++ standard的第12.8节([class.copy]
)给出了一个类似的例子:
class X {
// ...
public:
X(int);
X(const X&, int = 1);
};
X a(1); // calls X(int);
X b(a, 0); // calls X(const X&, int);
X c = b; // calls X(const X&, int);
最后一行是与你的情况匹配的那一行。