(ODR 使用问题)priority_queue 不同文件中的同名结构
(ODR-use question) priority_queue of identically named structs in different files
考虑以下文件:
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 ...
可以在 this gist.
中找到这两个程序的 valgrind 的确切输出
执行以下任一操作时不会出现错误:
- 用两个文件之一中的任何其他名称替换 "Event"
- 使两个结构大小相同
- 选择
main()
中的第二组两行而不是第一组
- 将
priority_queue
替换为 vector
,并使用 push_back
代替 push
我倾向于认为这是编译器中的一个问题(编译器错误?),其中 priority_queue
的两个版本的模板实例化方法的命名相互冲突。
这是一个已知问题,这是一个新错误,还是我遗漏了什么?
您违反了单一定义规则,因此您的程序具有未定义的行为。
要修复它,您可以将一个或两个结构放入命名空间中,使它们独一无二。如果在它们自己的 .cpp 文件之外不需要它们,您可以将它们分别放入一个匿名命名空间中。
如,这是 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 {
^
考虑以下文件:
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 ...
可以在 this gist.
中找到这两个程序的 valgrind 的确切输出执行以下任一操作时不会出现错误:
- 用两个文件之一中的任何其他名称替换 "Event"
- 使两个结构大小相同
- 选择
main()
中的第二组两行而不是第一组 - 将
priority_queue
替换为vector
,并使用push_back
代替push
我倾向于认为这是编译器中的一个问题(编译器错误?),其中 priority_queue
的两个版本的模板实例化方法的命名相互冲突。
这是一个已知问题,这是一个新错误,还是我遗漏了什么?
您违反了单一定义规则,因此您的程序具有未定义的行为。
要修复它,您可以将一个或两个结构放入命名空间中,使它们独一无二。如果在它们自己的 .cpp 文件之外不需要它们,您可以将它们分别放入一个匿名命名空间中。
如-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 {
^