2010-01-08 2 views
3

Я написал следующую программу, чтобы проверить, когда вызывается конструктор копирования и когда оператор присваивания называется:Конструкторы копирования и присваивания Операторы

 

#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 линии, чтобы сделать его более понятным):

 
[email protected]:~$ ./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 


второй и третий набор, ведут себя, как ожидалось, но в первом наборе копия строител ctor вызывается, даже если используется оператор присваивания.

Является ли это поведение части C++ стандарт или просто умные оптимизации компилятора (я использую GCC 4.4.1)

ответ

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 

инициализация копирование используется в тех случаях, которые соответствуют неявным преобразованиям, где один не явно Стартовых преобразования, как и в функции передачи аргументов и возвращение из функции.

2

Ваш первый набор соответствует стандарту C++ и не связан с некоторой оптимизацией.

Раздел 12,8 ([class.copy]) из C++ standard дает аналогичный пример:

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

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