c++staticundefined-referencemake-shared

Undefined reference to initialized static member variable with make_shared


Compiling with -std=c++14 the following code:

#include <memory>

class A
{
public:
    static constexpr int c = 0;
    std::shared_ptr<int> b;

    A()     {
        b = std::make_shared<int> (c);
    }

};

int main () {
    A a;
    return 0;
}

Gives a linker error "undefined reference to `A::c'", while using "A::c" in other contexts that are not "make_shared", this error doesn't occur. In particular, the following code compiles and works correctly:

class A
{
public:
    static constexpr int c = 0;
    std::shared_ptr<int> b;

    A()     {
        int cc = c;
        b = std::make_shared<int> (cc);
    }

};

Solution

  • Since C++17 the first code should work correctly: a static constexpr class member variable is implicitly inline which means the compiler takes care of making sure a definition exists .

    Prior to C++17 the code has undefined behaviour (no diagnostic required) due to ODR violation. A static class member that is odr-used must also have an out-of-line definition.

    Binding a reference to a variable counts as odr-use, and that happens with make_shared<int>(c) since that function is defined as :

    template< class T, class... Args >
    shared_ptr<T> make_shared( Args&&... args );
    

    so the argument is bound to a reference parameter.


    In theory you should be able to work around it with make_shared<int>(+c) ... then the reference is bound to the temporary result of +c and not to c itself, therefore there is no odr-use. Similar theory to your posted workaround in the question.

    enum { c = 0 }; is another possible workaround, if the type is int in the real code .