You're violating the One Definition Rule, resulting in Undefined Behaviour. This means literally anything can happen. Which includes working for some types involved and not others, or working only when the moon is full.
Segmentation fault when a member variable of type std::map is not declared in all compilation units [closed]
-
01-04-2022 - |
Pregunta
When I declare a member variable of type std::map
in one compilation unit but not the other, I get a segmentation fault when the containing object is being destructed. When I do the same with std::vector
, it works just fine.
It was definitely a bug in my case, and I fixed it, but I'm still wondering what's causing the crash.
Here's the code:
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;
}
Works fine with DECLARE_VECTOR
:
g++ -DDECLARE_VECTOR -c -o foo.o foo.cpp
g++ -o main main.cpp foo.o
But causes a segmentation fault with DECLARE_MAP
:
g++ -DDECLARE_MAP -c -o foo.o foo.cpp
g++ -o main main.cpp foo.o
Reproducible in clang 4.0 and gcc 4.4.7.
Can anybody explain why this happens?
Solución 2
Otros consejos
The problem is because you're doing the compilation in two steps and only in the first step do you define DECLARE_MAP
or DECLARE_VECTOR
. This results in two translation units that look like this:
foo.cpp
translation unit:// Contents of <map> // Contents of <string> class Foo { public: Foo(); private: std::map<std::string, std::string> m; }; int main() { Foo f; }
main.cpp
translation unit:// Contents of <map> // Contents of <string> class Foo { public: Foo(); private: }; int main() { Foo f; } int main() { Foo f; }
As you can see, each translation unit has a different definition of Foo
. The first has Foo
containing a std::map
and the second has it without.
This violates the following rule:
There can be more than one definition of a class type [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named
D
defined in more than one translation unit, then
each definition of
D
shall consist of the same sequence of tokens; and[...]
If the definitions of
D
do not satisfy these requirements, then the behavior is undefined.
As you can see, you have undefined behaviour. Yes, it might appear to work when you have DECLARE_VECTOR
, but that is only by chance. It still has undefined behaviour, so anything can happen.