复制构造函数和赋值运算符

Copy constructors and Assignment Operators

提问人:doron 提问时间:1/8/2010 最后编辑:Tim S. Van Harendoron 更新时间:1/8/2010 访问量:1044

问:

我编写了以下程序来测试何时调用复制构造函数以及何时调用赋值运算符:


#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)

C++ 复制构造函数

评论


答:

10赞 Johannes Schaub - litb 1/8/2010 #1

在第一个测试用例中不使用赋值运算符。它只是使用称为“复制初始化”的初始化形式。复制初始化在初始化对象时不考虑显式构造函数。

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

复制初始化用于与隐式转换相对应的情况,其中不显式启动转换,如函数参数传递和从函数返回。

2赞 stakx - no longer contributing 1/8/2010 #2

您的第一组是根据 C++ 标准,而不是由于某些优化。

C++ 标准的第 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);

最后一行将是与您的案例匹配的那一行。

3赞 Andreas Brinck 1/8/2010 #3

C++ 标准 8.5/12

在 参数传递、函数返回、 引发异常 (15.1), 处理 例外 (15.3),以及 大括号括起来的初始值设定项列表 (8.5.1) 称为复制初始化 等效于形式

T x = a;

在 new 中发生的初始化 表达式 (5.3.4)、static_cast 表达式 (5.2.9), 函数式 表示法类型转换 (5.2.3) 和 基初始值设定项和成员初始值设定项 (12.6.2) 称为直接初始化,并且是 等同于表单

T x(a);