2010-11-30 2 views
1

Мой 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» достаточно или это также вызовет утечку памяти?

ответ

6

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

b::~b() 
{ 
    delete pointer; 
} 
+3

Этого недостаточно. Предоставляя совет кому-либо, у которого явно нет опыта строительства/разрушения и указателей RAW, вы должны попытаться убедиться, что они не становятся для них опасными. В этой ситуации минимум должен также включать отключение конструктора копирования и оператора присваивания (или объяснить, как правильно их определить). – 2010-12-01 02:58:29

2
~b() { delete pointer; } 

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

+0

(Typo: Он означает «delete pointer;») – Marvo 2010-11-30 23:52:55

1

Да, это будет.

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

~b() { delete this->pointer; }
2

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

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

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

1

Другие ответы правильны, что вам нужно добавить деструктор, который удаляет член pointer. Я добавлю, что вам также, вероятно, нужен оператор копирования и оператор присваивания копии, который правильно обрабатывает этот указатель (Rule of Three).

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

1

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

~b() 
{ 
    delete pointer; 
} 

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

virtual ~b() 
{ 
    delete pointer; 
} 

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

1

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

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

0

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

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

0

В качестве ответов перед отмеченным классом «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

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

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

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

Смежные вопросы