Почему нет никаких утечек памяти в следующем C ++ при назначении? - PullRequest
4 голосов
/ 08 декабря 2011

следующий код опровергает мое убеждение, что я знаю C ++ более или менее.Почему valgrind не показывает здесь никакой утечки памяти?Почему я ожидаю memleaks:

  1. B больше, чем A: он содержит дополнительный элемент;поэтому при присваивании должна быть нарезка полей класса.
  2. ~ A () не имеет виртуального dtor.Поэтому, когда мы вызываем delete a, должен вызываться только ~A(), и память, выделенная в B., теряется.

Но я получаю, что порядок вызова dtors: ~ A (), ~ B (), ~ A ().Почему?!

struct A {
  ~A()
  {
      std::cerr << "~A" << std::endl;
  }
};

struct B : A {
  int* data;

  B() : data(new int[20]) {}

  ~B()
  {
    std::cerr << "~B" << std::endl;
    delete [] data;
  }
};

main():

A* a = new A;
B* b = new B;
*a = *b;

delete a;
delete b;

UPD: Позор мне!Я запутал удаление объекта указателем базового класса, когда должен вызываться виртуальный dtor.Вот только содержимое класса copying.Спасибо всем!

Ответы [ 7 ]

5 голосов
/ 08 декабря 2011
delete a;

a равно A*, поэтому A::~A называется

delete b;

b равно B*, поэтому B::~B называется.будет ли проблема?

Нарезка полей класса?Да так?Вы просто копируете поля A из *b в *a, не более того.Здесь не теряется память.

1 голос
/ 08 декабря 2011

Назначение *a = *b; копирует только общую часть данных AA не имеет полей).

1 голос
/ 08 декабря 2011

В *a = *b вы копируете (и да, нарезаете) *b в *a. Тем не менее, это оставляет *b без изменений; это не разрезано. Когда вы delete b, вы запрашиваете ~B() для вызова *b.

0 голосов
/ 08 декабря 2011

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

*a = *b 

Компилятор «нарезает» эти производные части объекта и копирует только базовую часть объекта.Обычно это не то, что нужно делать, потому что это приведет к неполному объекту с отсутствием только свойств базового класса и свойств специализированного производного класса.

0 голосов
/ 08 декабря 2011

Ваш класс A пуст, поэтому он совершенно не имеет значения для целей этого обсуждения. Единственный код, который участвует в динамическом размещении:

B* b = new B;
delete b;

Поскольку вы delete объект, созданный с помощью new, утечки нет. Кроме того, класс B содержит достаточный код для очистки своего внутреннего распределения в этом прямом примере использования.

(Обратите внимание, что class B по-прежнему ужасно нарушен, поскольку он не выживет при копировании или назначении. Классическое правило трех (или пяти).)

0 голосов
/ 08 декабря 2011

Вызывая *a = *b;, вы неявно вызываете функцию оператора присваивания, созданную компилятором, которая выглядит следующим образом:

A &operator=( const A &other ){
}

, которая в вашем случае ничего не делает, поскольку A имеетнет переменной-члена.

0 голосов
/ 08 декабря 2011

Вы сделали удаление для каждого нового, поэтому нет утечки памяти.

*a =*b

ничего не выделяет, конструктор копирования просто копирует часть b, которая может перейти к a, но не вызывает new ..

...