2015-09-09 2 views
2

Я написал следующий фиктивный класс, чтобы понять, как конструктор копирования, оператор копирующего присваивания и деструктор работы:динамическое распределение памяти, члены указателей и деструкторы

#include <string> 
#include <iostream> 

class Box { 

    public: 
    // default constructor 
    Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {} 
    // copy constructor 
    Box(const Box &other) { a=other.a; s=new std::string(*other.s); } 
    // copy assignment operator 
    Box &operator=(const Box &other) { a=other.a; s=new std::string(*other.s); } 
    // destructor 
    ~Box() { std::cout<<"running destructor num. "<<++counter<<std::endl; } 
    int get_int() { return a; } 
    std::string &get_string() { return *s; } 
    private: 
    int a; 
    std::string *s; 
    static int counter; 

}; 

int Box::counter=0; 

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

#include "Box.h" 

using namespace std; 

int main() 
{ 
    Box b1; 
    Box b2(2,"hello"); 
    cout<<b1.get_int()<<" "<<b1.get_string()<<endl; 
    cout<<b2.get_int()<<" "<<b2.get_string()<<endl; 
    Box b3=b1; 
    Box b4(b2); 
    cout<<b3.get_int()<<" "<<b3.get_string()<<endl; 
    cout<<b4.get_int()<<" "<<b4.get_string()<<endl; 
    b1=b4; 
    cout<<endl; 
    cout<<b1.get_int()<<" "<<b1.get_string()<<endl; 
    { 
    Box b5; 
    } // exit local scope,b5 is destroyed but string on the heap 
    // pointed to by b5.s is not freed (memory leak) 
    cout<<"exiting program"<<endl; 
} 

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

Кроме того, определяя этот оператор присваивания копии, у меня есть утечка памяти каждый раз, когда я назначаю объект (указатель указывает на новый объект в куче, а первый потерян, не так ли?)?

+0

Имеет посмотрите здесь: http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three –

+2

И да, ваш код просачивается, как сито. –

+0

@ πάνταῥεῖ да, вот и весь смысл .. – Luca

ответ

4

Каждый раз, когда вы вызываете новое, вы должны его удалить (кроме общих указателей).

Итак, вы должны удалить строку в деструкторе.

Оператор присваивания работает с существующим экземпляром, поэтому вы уже создали s и не должны создавать новую строку для s.

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

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

0

Один из возможных способов борьбы с неназванными динамически распределенными членами - сохранять их в контейнере каждый раз, когда они создаются (в объекте, функции и т. Д.), А затем запускать цикл for в деструкторе с оператором delete за которыми следуют элементы контейнера.

Вы можете сделать это с помощью вектора:

vector <string*> container; 

и вы можете использовать его следующим образом:

// define it in the private members of your class 
vector <string*> container; 

// use it when you create the string 
container.push_back(new dynamicallyAllocatedObject); 

// free memory in the destructor 
for(auto it = container.begin(); it != container.end(); ++it) delete *it; 
2

Имейте в распределении ума происходит на базовой конструкции, копировать конструкцию и удивительно условно на уступки

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

условие, чтобы наблюдать за это:

x = x; 

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

Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {} 
// copy constructor 
    Box(const Box &other) { cp(other); } 
// copy assignment operator 
    Box &operator=(const Box &other) { 
    if (&other != this) // guard against self assignment 
    { 
     rm(); 
     cp(other); 
    } 
    return *this; 
    } 
// destructor 
    ~Box() { rm(); } 
private: 
    void cp(const Box &other) {a=other.a; s=new std::string(*other.s); 
    void rm() { 
    std::cout<<"running destructor num. "<<++counter<<std::endl; 
    delete s; // prevents leaks 
    } 
Смежные вопросы