(ODR使用问题)不同文件中同名结构的priority_queue

时间:2018-10-03 12:34:07

标签: c++ g++ one-definition-rule

请考虑以下文件:

a.cpp

#include <queue>

struct Event {  
    int a;
};

static bool operator<(const Event &a, const Event &b) {
    return a.a < b.a;
}

void external_insert(std::priority_queue<Event> &pqu, Event event) {
    pqu.push(event);
}

int main() {
    // fails
    std::priority_queue<Event> pqu;
    external_insert(pqu, Event());

    // works
    // std::priority_queue<Event> pqu;
    // pqu.push(Event());
    return 0;
}

b.cpp

#include <queue>

struct Event {
    int a, b;
};

static bool operator<(const Event &a, const Event &b) {
    return a.a < b.a;
}

void some_unused_function() {
    std::priority_queue<Event> evqu;
    evqu.push(Event());
}

然后使用以下命令将这两个文件编译为两个可执行文件:

g++ a.cpp b.cpp -o ab
g++ b.cpp a.cpp -o ba

然后在valgrind下都运行:

valgrind ./ab
# ... ERROR SUMMARY: 0 errors from 0 contexts ...
valgrind ./ba
# ... ERROR SUMMARY: 2 errors from 2 contexts ...

这两个程序从valgrind的确切输出可以在this gist中找到。

执行以下任一操作均不会发生错误:

  • 在两个文件之一中用其他任何名称替换“事件”
  • 使两个结构的大小相同
  • main()中选择第二组两行,而不是第一行
  • priority_queue代替vector,并用push_back代替push

我倾向于认为这是编译器中的一个问题(编译器错误?),两个priority_queue版本的模板实例化方法的命名彼此冲突。

这是一个已知问题吗,这是一个新错误,还是我遗漏了一些东西?

2 个答案:

答案 0 :(得分:4)

您违反了“一个定义规则”,因此您的程序具有未定义的行为。

要修复此问题,可以将一个或两个结构放入命名空间中以使其唯一。如果不需要在自己的.cpp文件之外使用它们,则可以将它们每个都放置在匿名名称空间中。

答案 1 :(得分:1)

John Zwinck said一样,这是ODR违规。您可以使用-flto诊断此类违规行为:

$ g++ -O2 -flto a.cpp b.cpp 
a.cpp:3:8: warning: type 'struct Event' violates the C++ One Definition Rule [-Wodr]
 struct Event {
        ^
b.cpp:3:8: note: a different type is defined in another translation unit
 struct Event {
        ^
b.cpp:4:12: note: the first difference of corresponding definitions is field 'b'
     int a, b;
            ^
b.cpp:3:8: note: a type with different number of fields is defined in another translation unit
 struct Event {
        ^