【问题标题】:ambigous struct definition in different modules不同模块中的模棱两可的结构定义
【发布时间】:2017-10-29 11:04:13
【问题描述】:

我有一个带有 MS Visual Studio 2015 的大型 C++11 项目,它在两个模块(= 编译单元、cpp 文件)中定义了两个名称相同但内容不同的结构。由于结构仅在模块中定义和使用,而不是通过任何头文件导出以供共享使用,因此应该允许这样做,实际上编译器和链接器都不会报告任何错误或警告。但是在运行时,我从包含该结构的无序映射的构造函数中得到访问冲突。 Visual Studio 2017 也会出现此问题,但 gcc5.4 不会出现此问题。在我看来,这是一个编译器错误,但我不确定。 这是一些重现问题的最小化源代码,只需与任何可执行文件链接即可在 main() 之前的启动期间获取访问冲突。

模块1.cpp:

#include <unordered_map>
struct AmbigousStruct {
    int i1;
    int i2;
    int i3;
};
static const std::unordered_map<int, AmbigousStruct>
s_ambigousStructMap{
    { 0, { 0, 1, 2 } }
};

module2.cpp:

#include <unordered_map>
struct AmbigousStruct {
    int i1;
    int i2;
};
static const std::unordered_map<int, AmbigousStruct>
s_ambigousStructMap{
    { 0, { 0, 1 } }
};

问题似乎与在模板类(本例中为 unordered_map)中使用结构有关,因为它不会发生在结构的简单实例中,即 module2.cpp:

static const AmbigousStruct s_ambigousStructInstance{ 0, 1 };

【问题讨论】:

  • 这就是namespace 解决的问题!

标签: c++ visual-studio c++11 struct compiler-bug


【解决方案1】:

您有两种具有外部链接的类类型,它们具有相同的名称,在不同的翻译单元中定义。他们的成员不匹配,这是违反单一定义规则的。您的程序格式错误,无需诊断。

您需要在该结构定义上强制执行内部链接。 C++ 标准允许您使用匿名命名空间来做到这一点。事实上,匿名命名空间使得其中的一切都具有内部链接。所以你不需要 static 修饰符来处理其他事情:

namespace {
  struct AmbigousStruct {
    int i1;
    int i2;
  };
  const std::unordered_map<int, AmbigousStruct>
  s_ambigousStructMap {
    { 0, { 0, 1 } }
  };
}

【讨论】:

    【解决方案2】:

    这是一个链接器问题,而不是编译器错误。链接器将采用找到的第一个定义并忽略第二个。

    要解决此问题,请为仅在翻译单元中本地使用的任何内容使用未命名的命名空间:

    namespace { // Everything contained is only visible in the current 
                // translation unit
        struct AmbigousStruct {
            int i1;
            int i2;
            int i3;
        };
        const std::unordered_map<int, AmbigousStruct> s_ambigousStructMap {
            { 0, { 0, 1, 2 } }
        };
    }
    

    在另一个 .cpp 文件中相同。

    【讨论】:

    • 我当然知道这个问题可以通过匿名命名空间来解决。但问题仍然存在,当模块 1 和模块 2 由大型项目的不同开发人员交付时。这两个模块本身都不是错误的,编译器没有机会发现任何问题,因为它独立编译每个模块。在我的迷你示例中,由于异常在启动时立即发生,因此很容易找到错误,但考虑一个更复杂的示例,它可能仅出现在罕见的代码分支中。
    • 为什么我没有收到链接器错误,或者如果代码真的错误,至少会收到警告?为什么gcc5.4可以正常工作?
    猜你喜欢
    • 2019-09-13
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    相关资源
    最近更新 更多