2012-04-03 4 views
6

Я хотел бы знать, нужно ли мне писать деструктор в классах, когда я больше не использую raw-указатели? Просто повысьте интеллектуальные указатели.Умные указатели и деструктор

+0

Может @simchona знает что-то я делаю не так, но умные указатели не снизить потребность в очистке, они просто изменить, как (когда) это происходит. –

+2

Я читаю этот вопрос так же, как бы активировать интеллектуальные указатели сами по себе, избавиться от необходимости писать деструкторы практически во всех случаях? Это верно? – gymbrall

+0

@ Да, если у вас есть deep_pointer (или то, что он называется), вам не нужны назначения/move/destructor/constructors. (Хотя конструкторы могут иногда быть удобными) –

ответ

-2

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

+0

Все эти вещи можно очистить, обернув их в класс RAII, например 'smart_ptr'. С C++ 11 деструкторы класса должны быть редкими. –

+1

@Mooing Не шутить. Умные указатели/RAII значительно сокращают мой код, и мои деструкторы, как правило, пусты. Им нужно время, чтобы привыкнуть, но их стоит узнать наверняка. – Aura

10

Укреплять интеллектуальные указатели сами по себе не имеют никакого отношения к необходимости деструктора. Все, что они делают, - это удалить необходимость вызывать удаление в выделенной памяти, которую они эффективно управляют. Поэтому, сказав это, если до того, как вы начали использовать интеллектуальные указатели, все, что у вас было в ваших деструкторах, были вызовами для удаления и удаления [] освобождения памяти динамически выделенных членов класса, и теперь вы переключили все эти обычные указатели на интеллектуальные указатели, вы могли бы возможно, просто переключитесь на пустой деструктор, поскольку они теперь будут очищаться для себя, когда они выйдут из сферы действия.

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

Дайте мне знать, если это поможет.

+0

Все эти вещи можно очистить, обернув их в класс RAII, например 'smart_ptr'. С C++ 11 деструкторы класса должны быть редкими. –

4

Каждый тип ресурса должен иметь класс RAII для управления этим ресурсом. Если у вас также есть умный указатель с семантикой глубокой копии (довольно легко сделать), это все, что вам нужно, чтобы управлять своими ресурсами в 99,9% случаев. Я не знаю, почему не делает глубоких копий и не повышает интеллектуальный указатель, но если у вас есть эти две вещи, вам не нужно писать конструкторы копирования, перемещать конструкторы, операторы присваивания, перемещать операторы присваивания и деструкторы. Вы можете или не должны предоставлять другие конструкторы (включая конструктор по умолчанию), но это еще пять мест, чтобы совершать ошибки.

#include <memory> 

template<class Type, class Del = std::default_delete<Type> > 
class deep_ptr : public std::unique_ptr<Type, Del> { 
public: 
    typedef std::unique_ptr<Type, Del> base; 
    typedef typename base::element_type element_type; 
    typedef typename base::deleter_type deleter_type; 
    typedef typename base::pointer pointer; 

    deep_ptr() : base() {} 
    //deep_ptr(std::nullptr_t p) : base(p) {} //GCC no has nullptr_t? 
    explicit deep_ptr(pointer p) : base() {} 
    deep_ptr(pointer p, const typename std::remove_reference<Del>::type &d) : base(p, d) {} //I faked this, it isn't quite right 
    deep_ptr(pointer p, typename std::remove_reference<Del>::type&& d): base(p, d) {} 
    deep_ptr(const deep_ptr& rhs) : base(new Type(*rhs)) {} 
    template<class Type2, class Del2> 
    deep_ptr(const deep_ptr<Type2, Del2>& rhs) : base(new Type(*rhs)) {} 
    deep_ptr(deep_ptr&& rhs) : base(std::move(rhs)) {} 
    template<class Type2, class Del2> 
    deep_ptr(deep_ptr<Type2, Del2>&& rhs) : base(std::move(rhs)) {} 

    deep_ptr& operator=(const deep_ptr& rhs) {base::reset(new Type(*rhs)); return *this;} 
    template<class Type2, class Del2> 
    deep_ptr& operator=(const deep_ptr<Type2, Del2>& rhs) {base::reset(new Type(*rhs)); return *this;} 
    deep_ptr& operator=(deep_ptr&& rhs) {base::reset(rhs.release()); return *this;} 
    template<class Type2, class Del2> 
    deep_ptr& operator=(deep_ptr<Type2, Del2>&& rhs) {base::reset(rhs.release()); return *this;} 
    void swap(deep_ptr& rhs) {base::swap(rhs.ptr);} 
    friend void swap(deep_ptr& lhs, deep_ptr& rhs) {lhs.swap(rhs.ptr);} 
}; 

С этим классом (или подобным) вам совсем не нужно!

struct dog { 
    deep_ptr<std::string> name; 
}; 

int main() { 
    dog first; //default construct a dog 
    first.name.reset(new std::string("Fred")); 
    dog second(first); //copy construct a dog 
    std::cout << *first.name << ' ' << *second.name << '\n'; 
    second.name->at(3) = 'o'; 
    std::cout << *first.name << ' ' << *second.name << '\n'; 
    second = first; //assign a dog 
    std::cout << *first.name << ' ' << *second.name << '\n'; 
} 

Как показано на http://ideone.com/Kdhj8

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