Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Visual C++: Why class method from different compilation unit is called?

I have two separate compilation units without any header files:

Unit a.cpp:

#include <algorithm>
#include <vector>
class my_predicate
{
    const std::vector<int>& vec;
public:
    my_predicate(const std::vector<int>& container) : vec(container) { }

    bool operator() (size_t idx1, size_t idx2)
    {
        return vec[idx1] < vec[idx2];
    }
};

int main()
{
    std::vector<int> v1,v2;
    v1.resize(10);
    v2.resize(10);

    std::sort(v1.begin(), v1.end(), my_predicate(v2));
}

Unit b.cpp:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include <algorithm>
#include <vector>

class my_predicate
{
    const std::vector<char>& vec;
public:
    my_predicate(const std::vector<char>& container) : vec(container) { }

    bool operator() (size_t idx1, size_t idx2)
    {
        std::cout << "Why the operator from b.cpp is called?" << std::endl;
        return vec[idx1] < vec[idx2];
    }
};

void bar()
{
    std::vector<char> v1, v2;

    std::sort(v1.begin(), v1.end(), my_predicate(v2));
}

The key difference in my_predicate implementation is the type of container used: vector<int> and vector<char>.

Formally unit a.cpp should know nothing about class my_predicate from unit b.cpp.

Weird things starts when sort in main from a.cpp is executed:

  1. It calls the correct constructor from my_predicate in a.cpp
  2. And then for sorting, suddenly starts to call operator() from my_predicate in b.cpp which it mustn’t know.

This is reproduced in Debug mode as well, so Whole Program Optimization is turned off here.

Am I missing something and now class definitions globally visible or this is a compiler bug?

Magic happens only if I have a dummy call to my_predicate in b.cpp (see dummy unused function bar in b.cpp).

As a bonus, if I try to rename my_predicate in a.cpp with VS Rename tool (Ctrl+R,Ctrl+R), it offers to rename it in both files.

>Solution :

You’ve defined bool my_predicate::operator() differently in two translation units and your linker therefore could pick any of them – or refuse the redefinition. The actual class definitions are different too, so that’s another ODR violation.

In g++

g++ -o x a.o b.o

makes it use the definition in a.o, and

g++ -o x b.o a.o

makes it use the definition in b.o.

See Definitions and ODR (One Definition Rule).

To not cause these types of ODR violations when you create classes (and functions etc) in your implementation (.cpp) files, put them in anonymous namespaces.

// a.cpp
namespace { // anonymous namespace
class my_predicate {
    // a's definition
};
} // anonymous namespace
// b.cpp
namespace { // anonymous namespace
class my_predicate {
    // b's definition
};
} // anonymous namespace
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading