C ++: удалить структуру? - PullRequest
6 голосов
/ 09 июня 2010

У меня есть структура, содержащая указатели:

struct foo
{
    char* f;
    int* d;
    wchar* m;
}

У меня есть вектор общих указателей на эти структуры:

vector<shared_ptr<foo>> vec;

vec выделяется в стеке. Когда он выходит из области видимости в конце метода, вызывается его деструктор. (Правильно?) Это будет вызывать деструктор каждого элемента в векторе. (Верно?) Вызывает ли delete foo удаление только указателей, таких как foo.f, или это действительно освобождает память из кучи?

Ответы [ 6 ]

15 голосов
/ 09 июня 2010
delete foo;

удалит память, выделенную для структуры foo, которая включает в себя три указателя.Но память, на которую указывают сами указатели, будет удалена, только если вы реализуете деструктор, который явно удаляет их.

10 голосов
/ 09 июня 2010

Если вы динамически распределили foo, например:

foo* f = new foo;

, тогда delete f уничтожит динамически размещенный объект foo, включая содержащиеся в нем указатели, но не что-либона которые указывают указатели, если они действительно указывают на динамически размещенные объекты или массивы объектов.

Если вы назначили динамически распределенный объект foo (т.е. результат new foo) для shared_ptr (при условии tr1 или boost), тогда когда последний shared_ptr, ссылающийся на этот объект, выходит из области действия delete, будет вызван указатель, первоначально возвращенный new foo автоматически.Вам не нужно делать это вручную.

Если ваш объект (foo) содержит указатели на динамически размещаемые объекты, которыми он владеет (поэтому необходимо освободить его в конце времени жизни foo),тогда настоятельно рекомендуется написать деструктор для правильного освобождения этих объектов (что будет зависеть от того, как они распределены).

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

Вы также должны рассмотреть один или несколько конструкторов, чтобы гарантировать, что ваши члены-указатели инициализированы.Если элементы указателя никогда не инициализируются, то, если они не назначены в течение времени жизни foo, тогда они не будут ни нулевыми, ни указывать на действительный объект, и это может вызвать ошибку в вашем деструкторе.

1 голос
/ 09 июня 2010

В вашем вопросе, похоже, есть некоторая терминологическая путаница. Деструктор вектора вызовет деструкторы для shared_ptr элементов, которые, в свою очередь, будут внутренне выполнять delete для своих сохраненных указателей (при необходимости).

Вызов delete foo, где foo - указатель на struct foo, вызовет деструктор struct foo и затем освободит память, занятую *foo.

Разрушитель вышеупомянутого struct foo абсолютно ничего не делает. Это тривиально. If не будет предпринимать никаких попыток освободить память, указанную struct foo::f или другими членами. С чего бы это? Он не знает и не может знать, следует ли освободить эту память.

На самом деле, поскольку struct foo::~foo тривиально, компиляторы обычно даже не пытаются его вызвать.

1 голос
/ 09 июня 2010

Вы не вызываете delete f, где f - это объект типа foo, если f выделено в стеке. Вы также не вызываете delete f для выделенного в куче объекта типа foo, если этот адрес хранится в общем указателе. shared_ptr objets позвонит вам delete, когда освободится последняя ссылка.

Поскольку ваш вектор хранит умные указатели, они также выпадают из области видимости, когда ваш вектор выходит из области видимости, и вызывается деструктор foo и освобождается связанная с ним память. Память foo составляет всего 3 указателя. Не то, что эти указатели содержат.

Если члены foo распределены в куче, вам нужно delete выделить их отдельно. Например, может быть, внутри деструктора foo, если память, на которую они указывают, не распределяется между объектами.


Когда он выходит из области видимости в конце метода, вызывается его деструктор. (Верно?)

правый.

Это в свою очередь вызовет деструктор каждого элемента в векторе. (Верно?)

правый. Деструктор умного указателя.

или это на самом деле освобождает память из кучи?

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

1 голос
/ 09 июня 2010

Удаляет только указатели.

0 голосов
/ 09 июня 2010

Когда он [vec] выходит из области видимости в конце метода, вызывается его деструктор.(Верно?)
Правильно

Это, в свою очередь, вызовет деструктор каждого элемента в векторе.(Верно?)
Правильно, это удалит элементы shared_ptr в контейнере, и, если они последние, также элементы, которыми они делятся.

Вызывает ли delete foo...?
Вы не можете удалить foo, это структура.Вы можете удалить экземпляр foo.
Вызов delete вызывает деструктор и освобождает память для структуры foo.

Удаляет ли деструктор foo только указатели, такие как foo :: f илидействительно ли он освобождает память из кучи?
Это зависит от деструктора, в этом случае у вас есть деструктор по умолчанию и так ...
Нет, в следующем примере кода вы можете увидеть некоторыепричин, по которым деструктор по умолчанию, связанный с foo, не может автоматически очистить элементы, на которые ссылаются указатели.

{
 char ca='a', *cb=new char;
 int *i = (int*)malloc(sizeof(int));
 foo a;
 shared_ptr<foo> b = new foo();
 a.f = &ca;
 a.d = i;
 b.f = cb;
}
...