2016-08-18 10 views
1

Я немного смущен, потому что я был уверен, что это должно работать иначе. Посмотрите на этом примере кода:Объект не удаляется до того, как назначен новый

#include <iostream> 
#include <string> 

using namespace std; 

class base 
{ 
    public: 
    virtual ~base() = default; 
}; 

class derived : public base 
{ 
    private: 
    int a = 0; 
    int *b = nullptr; 
    std::string lol; 

    public: 
    derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; } 
    derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; } 

    virtual ~derived() { cout << "dtor " << lol << endl; delete b; } 

    virtual void superFunction() { cout << "OMG " << lol << endl; } 
}; 

int main() 
{ 
    derived a("a"); 
    derived b("b"); 
    a = b; 
} 

И выход программы со всеми оптимизациями ОТКЛ:

ctor a 
ctor b 
dtor b 
dtor b 

Я был уверен, что в этом случае компилятор должен генерировать код, который удаляет объект a и использует копию конструктор для создания нового объекта. Вместо этого он использует operator=, который он неявно объявляет.

Может кто-нибудь объяснить, почему? Или укажите мне на стандарт C++.

Спасибо.

+1

Если «компилятор» сначала удаляет 'a', что бы он скопировал в' b'? Во всяком случае, здесь нет копии, просто назначение. – juanchopanza

+0

связанные: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – vu1p3n0x

ответ

5

Когда вы пишете a = b;, оператор присваивания оператора компилятора будет автоматически сгенерирован, если не присутствует в коде и не будет помечен как удаленный. Конструктор копирования используется только тогда, когда вы пытаетесь инициализировать новый объект из другого объекта, как это:

derived a("a"); 
derived b = a; 

Кроме того, ваш код аварии перед основным возвращается, как он пытается удалить b, который указывает на ту же память от a и от b после a = b; присвоение по умолчанию.

Если вы хотите удалить a с помощью derived destructor после выполнения a = b;, все, что вам нужно, это идиома с копией и заменой. What is the copy and swap idiom? имеет отличный ответ о том, как это сделать в устаревшем и современном C++. Правильная реализация правила четверти из этого ответа прекрасно подойдет принципу DRY и поможет вам избежать проблем с памятью. Обратите внимание на потрясающий трюк с параметром прохождения с operator=по значению, что делает компилятор выбранным конструктором (копирование или перемещение) и позволяет вам писать только четыре метода, а не все five из них.