Яка різниця між оператором призначення та конструктором копій?


105

Я не розумію різниці між конструктором призначення та конструктором копій у C ++. Це приблизно так:

class A {
public:
    A() {
        cout << "A::A()" << endl;
    }
};

// The copy constructor
A a = b;

// The assignment constructor
A c;
c = a;

// Is it right?

Я хочу знати, як розподілити пам'ять конструктора призначення та конструктора копіювання?



Відповіді:


160

Конструктор копіювання використовується для ініціалізації раніше неініціалізованих об'єкт з даних якого - то іншого об'єкта.

A(const A& rhs) : data_(rhs.data_) {}

Наприклад:

A aa;
A a = aa;  //copy constructor

Оператор присвоювання використовується для заміни даних в раніше инициализирован об'єкт з даними якого - то іншого об'єкта.

A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}

Наприклад:

A aa;
A a;
a = aa;  // assignment operator

Ви можете замінити побудову копій на конструкцію за замовчуванням плюс призначення, але це буде менш ефективно.

(Як додаткове зауваження: мої реалізації вище є саме тими, які компілятор надає вам безкоштовно, тому не було б особливого сенсу реалізовувати їх вручну. Якщо у вас є одна з цих двох, швидше за все, ви керуєте деяким ресурсом вручну. У такому випадку, згідно Правила трьох , вам, швидше за все, також знадобиться інший плюс деструктор.)


4
Лише зауваження: Сьогодні (C ++ 11 далі) вони можуть бути явно дефолтними =default;.
Дедуплікатор

2
@Deduplicator Також важливо відзначити, що, дотримуючись класифікацій, які потребують тривіальних конструкторів, ви повинні = default їх там, де потрібен ctor за замовчуванням: просто реалізація порожнього тіла самостійно все ще вважається визначеним користувачем ctor і таким чином (на рівні Standardese ) не є тривіальним і дискваліфікує тип із класифікацій, які потребують тривіального ctor.
підкреслюй_d

@sbi Чи можу я сказати, що у випадку, якщо конструктор копіювання не використовується, а замість цього використовується оператор присвоєння, об'єкт створюється спочатку за допомогою виклику конструктора або з аргументами, або без аргументів, а потім використовується оператор присвоєння та присвоюються нові значення на основі RHS. Якщо використовується конструктор копіювання, все-таки буде викликаний той самий конструктор, але значення, які використовуються для ініціалізації, є від іншого об'єкта.
Раджеш

@Rajesh: Я розгублений у тому, що ви запитуєте, і моє відчуття таке, що ви також розгублені. :)Ви спробуєте ще раз пояснити, про що ви говорите?
sbi

1
@ CătălinaSîrbu: Можна. Вони є двома незалежними функціями.
sbi

41

Різниця між конструктором копій та оператором присвоєння викликає багато плутанини у нових програмістів, але насправді не все так складно. Підсумовуючи:

  • Якщо перед тим, як скопіювати, потрібно створити новий об'єкт, використовується конструктор копій.
  • Якщо новий об'єкт не повинен бути створений до того, як може відбутися копіювання, використовується оператор призначення.

Приклад оператора призначення:

Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator

Приклад конструктора копій:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor

Було б справедливо сказати, що оператор присвоєння ефективно поєднує знищення старого об'єкта зі створенням нового, але з умовами, що (1) якщо один із кроків знищення старого об'єкта буде скасовано один із кроків у побудові нового, обидва етапи можуть бути пропущені; (2) Оператори присвоєння не повинні робити нічого поганого, якщо об'єкт призначений самому собі.
supercat

навіщо робити, vector <A> v3а потім v3 = v2 (де v2раніше оголошені та містять елементи vector<A>) виклики мого явного Aконструктора копій замість operator=? Я очікував, що мене operator=зателефонують замість того, copy constructorщо мій v3об’єкт вже був оголошений у той час, коли я робив завдання
Cătălina Sîrbu

19

Перше - ініціалізація копії, друге - просто призначення. Не існує такого поняття, як конструктор призначення.

A aa=bb;

використовує створений компілятором конструктор копій.

A cc;
cc=aa;

використовує конструктор за замовчуванням для побудови cc, а потім оператор присвоєння * ( operator =) вже існуючого об'єкта.

Я хочу знати, як розподілити пам'ять конструктора призначення та конструктора копіювання?

IDK, що ви маєте на увазі, виділяючи пам'ять у цьому випадку, але якщо ви хочете побачити, що відбувається, ви можете:

class A
{
public :
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

Я також рекомендую поглянути на:

Чому конструктор копій називається замість конструктора перетворення?

Що таке правило трьох?


5

Простими словами,

Конструктор копіювання викликається, коли новий об’єкт створюється з існуючого об'єкта, як копія існуючого об'єкта. І оператор присвоєння викликається, коли вже ініціалізованому об'єкту присвоюється нове значення з іншого існуючого об'єкта.

Приклад-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"

4

Що реалізовано таким чином @Luchian Grigore Said

class A
{
public :
    int a;
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

void main()
{
    A sampleObj; //Calls default constructor
    sampleObj.a = 10;

    A copyConsObj  = sampleObj; //Initializing calls copy constructor

    A assignOpObj; //Calls default constrcutor
    assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}

ВИХІД


конструктор за замовчуванням


конструктор копій


конструктор за замовчуванням


оператор присвоєння



4

різниця між конструктором копій та конструктором призначення:

  1. У випадку конструктора копій він створює новий об'єкт. ( <classname> <o1>=<o2>)
  2. У разі конструктора присвоєння він не створить жодного об'єкта, значить, він застосовується до вже створених об'єктів ( <o1>=<o2>).

І основні функції в обох однакові, вони будуть копіювати дані з o2 в o1 член-член.


2

Я хочу додати ще одну точку до цієї теми. "Операційна функція оператора присвоєння повинна записуватися лише як функція-член класу." Ми не можемо зробити це функцією friend на відміну від інших бінарних або одинарних операторів.


1

Що додати про конструктор копій:

  • При передачі об'єкта за значенням він буде використовувати конструктор копій

  • Коли об’єкт повертається з функції за значенням, він буде використовувати конструктор копій

  • При ініціалізації об'єкта використовуються значення іншого об'єкта (як приклад, який ви наводите).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.