Jaka jest różnica między operatorem przypisania a konstruktorem kopiującym?

105

Nie rozumiem różnicy między konstruktorem przypisania a konstruktorem kopiującym w C ++. To wygląda tak:

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

// The copy constructor
A a = b;

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

// Is it right?

Chcę wiedzieć, jak przydzielić pamięć konstruktora przypisania i konstruktora kopiującego?

alan.chen
źródło
2
Czy masz dobrą książkę o C ++ ?
sbi
powiązane FAQ
fredoverflow

Odpowiedzi:

160

Konstruktor kopiujący służy do zainicjowania wcześniej niezainicjowanego obiektu z danych innego obiektu.

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

Na przykład:

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

Operatorowi przypisanie jest stosowany do zastąpienia danych o uprzednio inicjowane obiektu z innym obiektem danych użytkownika.

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

Na przykład:

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

Możesz zastąpić konstrukcję kopiowania domyślną konstrukcją plus przypisanie, ale byłoby to mniej wydajne.

(Na marginesie: moje implementacje powyżej są dokładnie tymi, które kompilator przyznaje ci za darmo, więc nie ma sensu ich implementować ręcznie. Jeśli masz jedną z tych dwóch, prawdopodobnie ręcznie zarządzasz jakimś zasobem. W takim przypadku, zgodnie z Regułą trzech , najprawdopodobniej będziesz potrzebować drugiego plus destruktora).

sbi
źródło
4
Uwaga: obecnie (od C ++ 11) można je jawnie ustawić jako domyślne =default;.
Deduplicator
2
@Deduplicator Należy również wspomnieć, że stosując się do klasyfikacji, które wymagają trywialnych konstruktorów, należy = default ich używać tam, gdzie potrzebny jest domyślny ctor: po prostu zaimplementowanie pustego ciała przez nas nadal liczy się jako zdefiniowany przez użytkownika, a zatem (na poziomie Standardese ) nie jest trywialny i dyskwalifikuje typ z klasyfikacji, które wymagają trywialnego ktora.
underscore_d
@sbi Czy mogę powiedzieć, że w przypadku, gdy konstruktor kopiujący nie jest używany, a zamiast tego używany jest operator przypisania, obiekt jest tworzony najpierw przez wywołanie konstruktora z argumentami lub bez argumentów, a następnie używany jest operator przypisania i nowe wartości są przypisywane na podstawie RHS. W przypadku użycia konstruktora kopiującego, zostanie wywołany ten sam konstruktor, ale wartości użyte do inicjalizacji pochodzą z innego obiektu.
Rajesh
@Rajesh: Nie rozumiem, o co pytasz, a wydaje mi się, że ty też jesteś zdezorientowany. :)Spróbujesz jeszcze raz wyjaśnić, o czym mówisz?
sbi
1
@ CătălinaSîrbu: Mógłbyś. Są to dwie niezależne funkcje.
sbi
41

Różnica między konstruktorem kopiującym a operatorem przypisania powoduje wiele zamieszania dla nowych programistów, ale nie jest to wcale takie trudne. Zreasumowanie:

  • Jeśli nowy obiekt musi zostać utworzony przed kopiowaniem, używany jest konstruktor kopiujący.
  • Jeśli nowy obiekt nie musi być tworzony przed kopiowaniem, używany jest operator przypisania.

Przykład operatora przypisania:

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

Przykład konstruktora kopiującego:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor
Bieg
źródło
Czy byłoby sprawiedliwe powiedzieć, że operator przypisania skutecznie łączy zniszczenie starego obiektu z utworzeniem nowego, ale z zastrzeżeniem, że (1) jeśli jeden z etapów zniszczenia starego obiektu zostałby cofnięty przez jeden z etapów budowy nowego, oba kroki można pominąć; (2) Operatory przypisania nie powinny robić złych rzeczy, jeśli obiekt jest przypisany do siebie.
supercat
dlaczego robisz vector <A> v3i wtedy v3 = v2 (gdziev2 jest poprzednio zadeklarowany i zawierający elementy vector<A>) wywołuje mój jawny Akonstruktor kopiujący zamiast operator=? Spodziewałem operator=się, że zadzwonię zamiast tego, copy constructorponieważ mój v3obiekt był już zadeklarowany w momencie, w którym wykonałem zadanie
Cătălina Sîrbu
19

Pierwsza to inicjalizacja kopiowania, druga to tylko przypisanie. Nie ma czegoś takiego jak konstruktor przypisania.

A aa=bb;

używa generowanego przez kompilator konstruktora kopiującego.

A cc;
cc=aa;

używa domyślnego konstruktora do konstruowania cc, a następnie * operatora przypisania ** ( operator =) na już istniejącym obiekcie.

Chcę wiedzieć, jak przydzielić pamięć konstruktora przypisania i konstruktora kopiującego?

IDK, co masz na myśli, mówiąc w tym przypadku o przydzieleniu pamięci, ale jeśli chcesz zobaczyć, co się stanie, możesz:

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

Polecam również przyjrzeć się:

Dlaczego zamiast konstruktora konwersji wywoływany jest konstruktor kopiujący?

Jaka jest zasada trzech?

Luchian Grigore
źródło
5

W prostych słowach

Konstruktor kopiujący jest wywoływany, gdy nowy obiekt jest tworzony z istniejącego obiektu, jako kopia istniejącego obiektu. Operator przypisania jest wywoływany, gdy do już zainicjowanego obiektu jest przypisywana nowa wartość z innego istniejącego obiektu.

Przykład-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"
Satish
źródło
4

To, co powiedział @Luchian Grigore, jest zaimplementowane w ten sposób

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
}

WYNIK


domyślny konstruktor


konstruktor kopiujący


domyślny konstruktor


operator przypisania


Mak
źródło
4

różnica między konstruktorem kopiującym a konstruktorem przypisania jest następująca:

  1. W przypadku konstruktora kopiującego tworzy nowy obiekt. ( <classname> <o1>=<o2>)
  2. W przypadku konstruktora przypisania nie utworzy on żadnego obiektu, czyli zastosuje się do już utworzonych obiektów ( <o1>=<o2>).

A podstawowe funkcje w obu są takie same, będą kopiować dane z o2 do o1 member-by-member.

Nitesh Kumar
źródło
2

Chcę dodać jeszcze jedną kwestię na ten temat. „Funkcja operatora przypisania powinna być zapisywana tylko jako funkcja składowa klasy”. Nie możemy sprawić, że będzie działał jako przyjaciel, w przeciwieństwie do innych operatorów binarnych lub jednoargumentowych.

MD BELAL RASHID
źródło
1

Coś do dodania o konstruktorze kopiującym:

  • Podczas przekazywania obiektu przez wartość użyje konstruktora kopiującego

  • Kiedy obiekt jest zwracany z funkcji przez wartość, użyje konstruktora kopiującego

  • Podczas inicjalizacji obiektu przy użyciu wartości innego obiektu (jak podano w przykładzie).

Frank Shen
źródło