Undefined reference error when initializing unique_ptr with a static const

江枫思渺然 提交于 2020-01-02 01:58:21

问题


When I try to use a static const to initialize a unique_ptr, I get an "undefined reference" error. However, when I new a pointer using the same constant, the symbol seems to be magically defined.

Here is a simple program that reproduces the error:

Outside_library.h

class Outside_library
{
public:
  static const int my_const = 100;
};

main.cpp

#include "Outside_library.h"

#include <iostream>
#include <memory>

class My_class
{
public:
  My_class(int num)
  {
    m_num = num;
  };

  virtual ~My_class(){};

private:
  int m_num;
};

int main(int, char* [])
{
  My_class* p_class = new My_class(Outside_library::my_const);
  delete p_class;

  // ==== ERROR HERE: When I comment this line out, the program runs fine.
  std::unique_ptr<My_class> p_unique
      = std::make_unique<My_class>(Outside_library::my_const);

  std::cout << "I made it through!" << std::endl;
  return 0;
}

I compiled the program using

g++ main.cpp -std=c++14

and got the following error.

/tmp/ccpJSQJS.o: In function `main':
main.cpp:(.text+0x51): undefined reference to `Outside_library::my_const'
collect2: error: ld returned 1 exit status

Can someone please help me understand why the constant is defined when using new, but not when using make_unique?


回答1:


C++ has something known as the One-Definition Rule (ODR):

Informally, an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it; a reference is odr-used if it is used and its referent is not known at compile time; and a function is odr-used if a function call to it is made or its address is taken. If an object, a reference or a function is odr-used, its definition must exist somewhere in the program; a violation of that is usually a link-time error.

The linked site gives the following example:

struct S {
    static const int x = 0; // static data member
    // a definition outside of class is required if it is odr-used
};
const int& f(const int& r);

int n = b ? (1, S::x) // S::x is not odr-used here
          : f(S::x);  // S::x is odr-used here: a definition is required

Your explicit constructor invocation does not "odr-use" Outside_library::my_const but the call to std::make_unique() does. When an object is odr-used it must have exactly one definition (not declaration). Your example has a declaration only. Again from cppreference:

  1. a variable x in a potentially-evaluated expression ex is odr-used unless both of the following are true:

    • applying lvalue-to-rvalue conversion to x yields a constant expression that doesn't invoke non-trivial functions
    • either x is not an object (that is, x is a reference) or, if x is an object, it is one of the potential results of a larger expression e, where that larger expression is either a discarded-value expression or has the lvalue-to-rvalue conversion applied to it

The solution as suggested by Jarod42 is to use constexpr instead of const (if you have control over the "outside library" code). If you do not, then you'll need to link the program against the library that contains the definition of Outside_library::my_const.

g++ main.cpp -std=c++14 -lOutside_library



回答2:


make_unique takes (forwardind) reference of its parameter, and so odr-use it.

My_class(Outside_library::my_const) only use the value.

One solution is to define the member in a TU:

const int Outside_library::my_const;

or using constexpr value (since C++11):

class Outside_library
{
public:
    static constexpr int my_const = 100;
};



来源:https://stackoverflow.com/questions/48428550/undefined-reference-error-when-initializing-unique-ptr-with-a-static-const

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!