6

複数の仮想デストラクタについて、特に考え直しました。http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspxを読んだ後。

私が持っているとしましょう

class Base
{
    public:
        Base();
        virtual ~Base();

    private:
        Logger* _logger;
};

//and

class Derived : public Base{
    public:
        Derived();
        virtual ~Derived();

    private:
        Logger* _logger;
};

cppファイルで、各デストラクタでそれぞれの_loggerポインタを削除しています

Base::~Base(){  //base.cpp
    delete _logger;
}
Derived::~Derived(){ //derived.cpp
    delete _logger;
}

これは意図したとおりに機能し、メモリ リークは発生しませんか?

4

2 に答える 2

5

まず、基本クラスを destructorにすると、すべての派生クラスは、宣言するかどうかにかかわらずvirtual、自動的にデストラクタを取得します。これは通常、署名の一致に当てはまります。基本クラスに派生クラスの関数と同じ署名を持つ関数がある場合、派生クラスの関数はand です(ただし、C++ 2011 では、キーワードを使用してそれ以上のオーバーライドを防ぐことができます)。その場合、別のオーバーライドでエラーが発生します)。virtualvirtualvirtualoverridevirtualfinal

とはいえ、デストラクタは特別です。デストラクタを作成すると、virtualオーバーライドする別のデストラクタがあっても呼び出されます! デストラクタが存在することの唯一の影響は、オブジェクトが実際に派生型である場合に、基底クラスへのポインタを使用するvirtual場合に何が起こるかです。デストラクタは。例えば:deletevirtualvirtual

class not_a_base {};
class bad_idea: public not_a_base {};

class a_base { public: virtual ~a_base() {} };
class ok: public a_base {};

int main() {
    a_base* ab = new ok;
    delete ab; // <---- all is good here!

    not_a_base* nab = new bad_idea;
    delete nab; // <---- results in undefined behavior
}

デストラクタがvirtualデフォルトではない理由は、オブジェクトのサイズが常に一般に受け入れられないワードサイズだけ増加することを意味するからです。

于 2012-11-17T00:48:45.713 に答える
4

Base::_loggerは別の変数ですDerived::_loggerDerived::_loggerしたがって、Derived の dctor で削除する必要があります。そうしないと、メモリ リークが発生します。

これはプライベートであることとは何の関係もないことに注意してください。次のサンプル プログラムを検討してください。

#include <iostream>

class A {
public:
    bool foo;
};

class B: public A {
public:
    bool foo;
};

int main()
{
    B b;
    std::cout << &b.B::foo << ' ' << &b.A::foo << '\n';
}

アドレスが異なります。つまり、同じ名前を持っていても、それらは異なる変数です。これは、各クラスが独自の名前空間を導入しているため可能であり、名前が実際に衝突することはありません。最初は A::foo で、もう 1 つは B::foo です。

デストラクタは仮想であるため、両方が呼び出さ_loggerれ、両方で正しいものが削除されます。

于 2012-11-17T00:44:52.920 に答える