Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Вызов деструктора после


Автор: Rickert 20.4.2009, 10:46
Есть класс:
Код
class aPacket
{
  public:
    inline char* apGetData() const            {return data;}
    inline unsigned long apGetLength() const  {return length;}
    inline char apGetType() const             {return type;}

    aPacket(char* in);
      void apClearPacket();
      void apChewPacket(char* in = 0);
      virtual void apApartPacket() {};

    virtual ~aPacket() = 0;

  protected:
    char* data;
    unsigned long length;
};

От него наследую:
Код
class aPacketIni : public aPacket
{
  public:
    aPacketIni(char* in);
      void apApartPacket();
      void aPreparePacket();

      const aPacketIni operator=(const aPacketIni& p);

    ~aPacketIni();
};

Описание второго:
Код
const aPacketIni aPacketIni::operator=(const aPacketIni& p)
{
  apClearPacket();//функция чистит дин. созданную информацию

  length = p.apGetLength();
  data = new char[length];
  memcpy(data, p.apGetData(), length);
  type = p.apGetType();

  this->version = p.version;

  return (*this);
}

//=============================================================================

aPacketIni::~aPacketIni()
{
  apClearPacket();
}

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

Автор: azesmcar 20.4.2009, 11:01
Rickert

Видимо потому что оператор присваивания возвращает обьект по значеню а не по ссылке smile

Автор: Rickert 20.4.2009, 11:06
Да, так и есть. Тогда я не понимаю почему у меня второй класс работает нормально. Пошёл искать ошибку. Спасибо!
solved smile 

Автор: pompei 20.4.2009, 11:06
Как создаёте: в стеке или в куче?

Автор: math64 20.4.2009, 11:38
А рекурсии почему не возникает? По return (*this); объект должен скопироваться в место, предоставленное вызвавшей функцией для помещения результата, а для этого должен быть вызван оператор копирования.

Автор: zim22 20.4.2009, 11:40
Цитата(math64 @  20.4.2009,  11:38 Найти цитируемый пост)
А рекурсии почему не возникает? По return (*this); объект должен скопироваться в место, предоставленное вызвавшей функцией для помещения результата, а для этого должен быть вызван оператор копирования.

вы случайно не путаете конструктор копирования с оператором присвоения?

Автор: math64 20.4.2009, 13:36
Понятно. По return (*this); создаётся новый объект с помощью копирующего конструктора (а не оператора копирования), поскольку было выделено место для объекта, а объект ещё был не создан. Поскольку копирующий конструктор не определён, компилятор создаст его сам (причём неправильный - скопруется указатель data, а не будет выделятся новая память). Таким образом, у двух объектов будут одинаковые data. После выхода из оперетора копирования, поскольку результат операции никуда не присваивается и больше не нужен, вызывается деструктор и data удаляется. В скопированном объекте data указывает на удалённую память.
Вывод: 
  1. operator=() должен возвращать ссылку или ничего, его агрумент тоже должен быть ссылкой (но возможны исключения)
  2. Вместе с operator=() нужно создавать копирующий конструктор, чтобы они работали согласованно.

Автор: zim22 20.4.2009, 13:48
Цитата(math64 @  20.4.2009,  13:36 Найти цитируемый пост)
2. Вместе с operator=() нужно создавать копирующий конструктор, чтобы они работали согласованно.

и деструктор тоже нужно свой определить.

Автор: azesmcar 20.4.2009, 14:45
math64
1. Для класса автоматически буду сгенерированы (если они нужны и если они не написаны пользователем)
  • Дефолт конструктор
  • Копирующий конструктор
  • Деструктор
  • Оператор присваивания
2. Писать свои стоит лишь в том случае - если они будует отличатся от сгенерированных.
3. Если вам понадобилось явно написать копирующий конструктор или оператор присваивания - скорее всего нужно написать все 4.

Вот в принципе базовые правила для так называемой "Большой четверки" smile

Автор: zim22 20.4.2009, 14:53
Цитата(azesmcar @  20.4.2009,  14:45 Найти цитируемый пост)
Вот в принципе базовые правила для так называемой "Большой четверки"

а я знаю большую тройку. и дефолт конструктор в ней не обязателен.

Цитата

Существует весьма полезное эмпирическое правило: если класс нуждается в деструкторе, потребуются также оператор присвоения и конструктор копий. Это правило зачастую называют "правилом трёх" (Rule of Three), поскольку когда необходим деструктор, необходимы все три элемента управления копированием.

Автор: azesmcar 20.4.2009, 14:56
Цитата

а я знаю большую тройку. и дефолт конструктор в ней не обязателен.

А где я писал что обязателен?

Автор: zim22 20.4.2009, 14:58
Цитата(azesmcar @  20.4.2009,  14:56 Найти цитируемый пост)
А где я писал что обязателен?

здесь. не прямо, но косвенно smile
Цитата(azesmcar @  20.4.2009,  14:45 Найти цитируемый пост)
3. Если вам понадобилось явно написать копирующий конструктор или оператор присваивания - скорее всего нужно написать все 4.

Автор: azesmcar 20.4.2009, 14:59
zim22

Цитата

скорее всего нужно


Цитата

обязателен


разницы нет?

Автор: zim22 20.4.2009, 15:01
azesmcar, любите же вы придираться к словам  smile 

Автор: azesmcar 20.4.2009, 15:05
Цитата

azesmcar, любите же вы придираться к словам  smile  

Я? smile
Конструктор скорее всего понадобится потому что если в классе есть что копировать или присваивать (причем не тривиально а нужен для этого свой оператор/копирующий конструктор) то скорее всего нужен конструктор чтобы его проинициализировать. Это может и не быть дефолт конструктор, но какой-то понадобится. Это типа рекомендации над чем надо задумываться когда пишешь и вовсе не означают что они обязательны.

Автор: Rickert 21.4.2009, 02:37
Всё верно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)