2

私が自分のプロジェクトに取り組んでいたときに、これを偶然に発見しました。基本的に、私のプロジェクトでは、リソース処理のために以下のようなものがあります。

class Resource {
public:
    static Resource instance_;
    ~Resource () {
        std::for_each(res_.begin(), res_.end(), [&] (Stuff *stuff) {
            delete stuff;
        });
    }
private:
    std::set<Stuff*> res_;
};

これをもう一度valgrindで実行すると、プログラムの終了時に、いくつかの本当に不可解なエラーが表示されます。このようなもの:

by 0x40DD42: std::_Rb_tree<unsigned int, std::pair<unsigned int const, std::pair<Vertex*, unsigned int> >, 
std::_Select1st<std::pair<unsigned int const, std::pair<Vertex*, unsigned int> > >, std::less<unsigned int>, 
std::allocator<std::pair<unsigned int const, std::pair<Vertex*, unsigned int> > > >::equal_range(unsigned int const&)
\\ a lot, lot more to come...

Resourceこれらすべてを読むと、のデストラクタがすでに解放されているメモリ領域を解放していることを示しているようです。

しかし、私のデストラクタは間違いなく物事を正しく処理しています。これを証明するために、削除コードをデストラクタから別のメンバー関数に移動しました。だから、このようなもの:

class Resource {
public:
    static Resource instance_;
    ~Resource () { /* does nothing */ }
    void clear () {
        std::for_each(res_.begin(), res_.end(), [&] (Stuff *stuff) {
            delete stuff;
        });
    }
// ... more
};

次に、プログラムが終了する前に、静的インスタンスでclear()を呼び出すだけです。これで、valgrindにエラーが表示されなくなりました。

これが、プログラムが停止したときに静的インスタンスが停止した場合にのみ関係することをさらに証明するために、静的インスタンスを削除しました。静的なinstance_を使用する代わりに、プログラムの起動時Resourceにスタック上のインスタンスを割り当てました。main()この変更後、問題もなくなります。

さて、なぜこれが起こっているのだろうか?これはオペレーティングシステムと関係がありますか?

私の推測では、OSはおそらくプログラムが終了するときにすべてを解放しようとし、私のデストラクタはクリーンアップの前ではなく、クリーンアップ中にたまたま起動します。

ここで問題となっているOSはLinux(Ubuntu 12.10)です。コンパイラはgcc4.7.2です。

ありがとう

4

2 に答える 2

2

私は Xubuntu 12.10 を実行しています。私の gcc バージョンはあなたのものと一致します:

$ gcc --version
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

このテスト ケースでは:

#include <set>
#include <algorithm>

class Thing {};

class Test {
public:
    static Test test;

    std::set<Thing*> things;

    ~Test() {
        std::for_each(things.begin(), things.end(), 
                      [&](Thing* thing){ 
                          delete thing; 
                      });
    } 
};

Test Test::test;

int main() {
    Test::test.things.insert(new Thing());
    Test::test.things.insert(new Thing());

    return 0;
}

そしてvalgrind、すべて問題なく、4 つの割り当て、4 つの解放が報告されます。同じテストケースを試すとどうなりますか?

于 2012-11-01T01:27:22.550 に答える
0

[ディープ] コピー コンストラクターと関連する代入演算子を実装するのを忘れていました。

のインスタンスのコピーを作成するとどうなりますResourceか? delete最初のコピーは最終的に破棄され、次に 2 番目のコピーは最終的に破棄されます...そして、各コピーの破棄は同じポインターのイオンにつながります。良くない。

つまり、 3 のルールを実装するのを忘れていました。C++ の本の用語集でこれを調べてください。確かにそこにあるからです。

于 2012-11-01T01:32:58.687 に答える