Приведет ли это к утечке памяти? - PullRequest
1 голос
/ 01 декабря 2010

Мой C ++ довольно ржавый, так что теперь, когда я начал использовать его для хобби-проекта, я попал "на уровень выше" - снова ...

#include "stdafx.h"
#include "stdlib.h"

class a
{
public:
    void call() { printf("CALL called\n"); }
};

class b
{
public:
    b() { this->pointer = new a; }
    void call() { this->pointer->call(); }
private:
    a* pointer;
};

int _tmain(int argc, _TCHAR* argv[])
{
    b t;
    t.call();

    system("PAUSE");
    return 0;
}

Не приведет ли это к утечке памяти?И как я могу удалить указатели, если программа решит, что они им больше не нужны?

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

Ответы [ 10 ]

6 голосов
/ 01 декабря 2010

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

b::~b()
{
    delete pointer;
}
2 голосов
/ 01 декабря 2010

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

Старомодный способ справиться с этим - удалить указатель в деструкторе b, поскольку вы знаете, что его больше никогда нельзя будет использовать.

Более новый метод заключается в использовании «умного указателя», такого как boost :: shared_ptr (или std :: auto_ptr, если необходимо), а не простого указателя на объект.

2 голосов
/ 01 декабря 2010
~b() { delete pointer; }

Для каждого нового должно быть соответствующее удаление.

1 голос
/ 01 декабря 2010

Вы не можете удалить t, это не указатель. У вас может быть метод в b, называемый «release», который удаляет указатель раньше, если вы хотите. В этом примере a выглядит немного как «pImpl» для b, то есть оно используется для реализации идентичного вызова в b.

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

1 голос
/ 01 декабря 2010

1) Да, это приведет к утечке памяти, поскольку a выделяется динамически, но никогда не освобождается.
2) Нет - delete t будет недостаточно, поскольку t отвечает за управление / освобождение своего собственногоресурсы.
Чтобы исправить это, вам нужно написать деструктор для b, т. е.

~b()
{
   delete pointer;
}

Однако, чтобы быть сверхбезопасным, вы также можете сделать деструктор виртуальным
, т. е.

virtual ~b()
{
   delete pointer;
}

Это обеспечит вызов правильного деструктора в любых производных классах
HTH

1 голос
/ 01 декабря 2010

Все остальные ответы верны, что вам нужно добавить деструктор, который удаляет элемент pointer. Я добавлю, что вам, вероятно, также понадобится конструктор копирования и оператор присваивания, которые правильно обрабатывают этот указатель ( Правило трех ).

Кроме того, я предлагаю вам взглянуть на умные указатели, такие как boost :: shared_ptr (который в C ++ 0x станет std :: shared_ptr).

1 голос
/ 01 декабря 2010

Да, будет.

Вы должны добавить эту функцию к вашему b классу:

~b() { delete this->pointer; }
0 голосов
/ 12 апреля 2013

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

Одна из «проблем» с C ++ - это владение.Т.е. кому принадлежит что и кому надо что удалять.Только тщательный дизайн класса помогает решить эту проблему и уменьшить утечки памяти.

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

0 голосов
/ 01 декабря 2010

В качестве ответов ранее отмеченного класса «b» должен быть деструктор, удаляющий память, выделенную в конструкторе.Однако, как прокомментировал Мартин Йорк выше, это не исчерпывающий ответ.Как он отметил, здесь есть проблемы, о которых вам нужно позаботиться в отношении конструктора копирования и оператора присваивания, но я бы пошел еще дальше: прекратите использовать необработанные указатели и немедленно начните использовать умные указатели Boost .

Класс "b" переписан для использования boost :: shared_ptr <>:

class b
{
public:
    b() { this->pointer.reset(new a); }
    void call() { this->pointer->call(); }
private:
    boost::shared_ptr<a> pointer;
};

Обратите внимание на две вещи:

  1. Нам не нужно писать явный деструктор как shared_ptr автоматически уничтожит объект, на который он указывает (дополнительную информацию об условиях см. в документации по нему).
  2. Нам не нужно писать явный конструктор копирования или оператор присваивания, если мелкая копия объекта указанаpointer достаточно, потому что shared_ptr снова позаботится об этом автоматически, предоставив свой собственный конструктор копирования "мелкой копии" и операторы присваивания.

В следующем стандарте C ++ 0x также есть несколько умных указателейв том числе shared_ptr.Также смотрите scoped_ptr, а также shared_array и scoped_array в Boost.Это последнее, что я считаю особенно полезным при работе с C API, такими как Win32.

0 голосов
/ 01 декабря 2010

Технически нет утечки памяти, потому что программа завершается после завершения паузы. Когда программа завершается, вся выделенная ей память освобождается.

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

...