9

生のポインターを使用しなくなった場合、クラスにデストラクタを記述する必要があるかどうかを知りたいですか? スマートポインターをブーストするだけです。

4

3 に答える 3

13

Boost スマート ポインタ自体は、デストラクタの必要性とは何の関係もありません。彼らが行うことは、彼らが効果的に管理している割り当てられたメモリで削除を呼び出す必要をなくすことだけです。つまり、スマート ポインターの使用を開始する前に、デストラクタにあったのは、動的に割り当てられたクラス メンバーのメモリを解放する delete および delete[] の呼び出しだけであり、これらすべての通常のポインターをスマート ポインターに切り替えた場合、スコープ外に出たときに自分でクリーンアップするようになったため、おそらく空のデストラクタに切り替えるだけです。

ただし、何らかの理由で、クリーンアップ (ファイルのクリーンアップ、ソケット、その他のリソースなど) を行う必要があるクラスがある場合は、それを行うためのデストラクタを提供する必要があります。

それが役立つかどうか教えてください。

于 2012-04-03T20:07:51.973 に答える
4

各リソース タイプには、そのリソースを管理するための RAII クラスが必要です。ディープ コピー セマンティクスを備えたスマート ポインターもあれば (実行は非常に簡単です)、リソースを 99.9% の確率で管理するために必要なのはそれだけです。ディープ コピーやブースト スマート ポインターを実行しない理由はわかりunique_ptrませんが、これら 2 つがあれば、コピー コンストラクター、ムーブ コンストラクター、代入演算子、ムーブ代入演算子、デストラクターを記述する必要はありません。他のコンストラクター (既定のコンストラクターを含む) を提供する必要がある場合と提供しない場合がありますが、これにより、間違いを犯す場所が 5 つ少なくなります。

#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で示されているように

于 2012-04-03T20:21:43.517 に答える
-2

デストラクタの提供を常に検討する必要があります。これを使用して、クラスが保持しているリソースを解放します。多くの場合、smart_ptrクラスのデストラクタは空ですが、常にそうであるとは限りません。ファイルストリーム、データベース接続などはすべて適切なクリーンアップが必要です。

于 2012-04-03T20:02:08.487 に答える