-1

当我在一个编译单元中声明一个类型的成员变量std::map而不在另一个编译单元中时,当包含对象被破坏时,我会遇到分段错误。当我对 做同样的事情时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()
{
}

主.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

问题是因为您分两步进行编译,并且仅在第一步中定义DECLARE_MAPor DECLARE_VECTOR。这会产生两个如下所示的翻译单元:

  • 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. 第一个Foo包含a std::map,第二个没有。

这违反了以下规则:

如果每个定义出现在不同的翻译单元中,并且定义满足以下要求,则程序中可以有多个类类型的定义[...]。给定这样一个D在多个翻译单元中定义的实体,那么

  • 的每个定义D应由相同的标记序列组成;和

  • [...]

如果 的定义D不满足这些要求,则行为未定义。

如您所见,您有未定义的行为。是的,当您拥有 时,它可能会起作用DECLARE_VECTOR,但这只是偶然。它仍然有未定义的行为,所以任何事情都可能发生。

于 2013-04-04T14:08:06.820 回答
1

您违反了单一定义规则,导致未定义行为。这意味着从字面上看,任何事情都可能发生。其中包括为某些涉及的类型而不是其他类型工作,或者仅在满月时工作。

于 2013-04-04T14:06:21.567 回答