-1

タイプのメンバー変数をstd::map1 つのコンパイル ユニットで宣言し、他のコンパイル ユニットでは宣言しない場合、含まれているオブジェクトが破棄されているときにセグメンテーション エラーが発生します。で同じことをするとstd::vector、うまくいきます。

私の場合は間違いなくバグであり、修正しましたが、何がクラッシュの原因なのかまだ疑問に思っています。

コードは次のとおりです。

foo.hpp:

#ifdef DECLARE_MAP
#include <map>
#endif
#ifdef DECLARE_VECTOR
#include <vector>
#endif
#include <string>

class Foo {
public:
    Foo();

private:
#ifdef DECLARE_MAP
    std::map<std::string, std::string> m;
#endif
#ifdef DECLARE_VECTOR
    std::vector<std::string> v;
#endif
};

foo.cpp:

#include "foo.hpp"

Foo::Foo()
{
}

main.cpp:

#include "foo.hpp"

int main()
{
    Foo f;
}

正常に動作しDECLARE_VECTORます:

g++ -DDECLARE_VECTOR -c -o foo.o foo.cpp
g++ -o main main.cpp foo.o

しかし、次の場合にセグメンテーション違反が発生しDECLARE_MAPます。

g++ -DDECLARE_MAP -c -o foo.o foo.cpp
g++ -o main main.cpp foo.o

clang 4.0 および gcc 4.4.7 で再現可能です。

なぜこれが起こるのか誰か説明できますか?

4

2 に答える 2

2

問題は、コンパイルを 2 つのステップで実行していて、最初のステップでのみDECLARE_MAPorを定義しているためDECLARE_VECTORです。これにより、次のような 2 つの翻訳単位が生成されます。

  • foo.cpp翻訳単位:

    // Contents of <map>
    // Contents of <string>
    
    class Foo {
    public:
        Foo();
    
    private:
        std::map<std::string, std::string> m;
    };
    
    int main()
    {
        Foo f;
    }
    
  • main.cpp翻訳単位:

    // Contents of <map>
    // Contents of <string>
    
    class Foo {
    public:
        Foo();
    
    private:
    };
    
    int main()
    {
        Foo f;
    }
    
    int main()
    {
        Foo f;
    }
    

ご覧のとおり、翻訳単位ごとに の定義が異なりますFoo。最初のものはFooa を含みstd::map、2 番目のものはそれなしです。

これは次の規則に違反します。

各定義が異なる翻訳単位に現れ、定義が次の要件を満たしている場合、プログラムにはクラス型 [...] の複数の定義が存在する可能性があります。D複数の翻訳単位で定義されたそのような名前のエンティティが与えられた場合、

  • の各定義はD、同じ一連のトークンで構成されます。と

  • [...]

の定義がDこれらの要件を満たさない場合、動作は未定義です。

ご覧のとおり、未定義の動作があります。はいDECLARE_VECTOR。まだ未定義の動作なので、何でも起こりえます。

于 2013-04-04T14:08:06.820 に答える
1

1 つの定義ルールに違反しているため、未定義の動作が発生します。これは、文字通り何でも起こり得ることを意味します。これには、関連する特定のタイプで働き、他のタイプでは働かない、または満月のときにのみ働くことが含まれます。

于 2013-04-04T14:06:21.567 に答える