Search code examples
c++g++one-definition-rule

(ODR-use question) priority_queue of identically named structs in different files


Consider the following 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());
}

Then compile these two files to two executables using:

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

And then run both under valgrind:

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

The exact output from valgrind for the two programs can be found in this gist.

No errors occur when doing either of the following things:

  • Replacing "Event" with any other name in one of the two files
  • Making both structs the same size
  • Choosing the second set of two lines in main() instead of the first
  • Replacing the use of priority_queue with vector, and using push_back instead of push

I'm inclined to believe this is an issue in the compiler (compiler bug?) where the naming for the template-instantated methods for the two versions of priority_queue conflict with each other.

Is this a known issue, is this a new bug, or am I missing something?


Solution

  • You have violated the One Definition Rule, so your program has undefined behavior.

    To fix it, you can put one or both structs into a namespace to make them unique. If they are not needed outside their own .cpp files, you can put them each into an anonymous namespace.