简体   繁体   English

使用静态const初始化unique_ptr时未定义的引用错误

[英]Undefined reference error when initializing unique_ptr with a static const

When I try to use a static const to initialize a unique_ptr , I get an "undefined reference" error. 当我尝试使用static const来初始化unique_ptr ,我得到一个“未定义的引用”错误。 However, when I new a pointer using the same constant, the symbol seems to be magically defined. 但是,当我使用相同的常量new一个指针时,符号似乎是神奇地定义的。

Here is a simple program that reproduces the error: 这是一个重现错误的简单程序:

Outside_library.h Outside_library.h

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

main.cpp 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 ? 有人可以帮我理解为什么在使用new时定义常量,而不是在使用make_unique

C++ has something known as the One-Definition Rule (ODR) : C ++有一种称为单一定义规则(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; 如果使用引用并且在编译时不知道它的引用,则引用是odr-used; 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. 你的显式构造函数调用不是“odr-use” Outside_library::my_const而是对std::make_unique()的调用。 When an object is odr-used it must have exactly one definition (not declaration ). 当一个对象使用odr时,它必须只有一个定义 (不是声明 )。 Your example has a declaration only. 您的示例仅包含声明。 Again from cppreference : 再次来自cppreference

  1. a variable x in a potentially-evaluated expression ex is odr-used unless both of the following are true: 除非满足以下两个条件,否则在可能评估的表达式ex中的变量x是odr-used:

    • applying lvalue-to-rvalue conversion to x yields a constant expression that doesn't invoke non-trivial functions 将lvalue-to-rvalue转换应用于x会产生一个不调用非平凡函数的常量表达式
    • 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 x不是一个对象(也就是说,x是一个引用),或者,如果x是一个对象,它是一个较大的表达式e的潜在结果之一,其中较大的表达式是一个丢弃值表达式或具有应用了左值到右值的转换

The solution as suggested by Jarod42 is to use constexpr instead of const (if you have control over the "outside library" code). Jarod42建议的解决方案是使用constexpr而不是const (如果您可以控制“外部库”代码)。 If you do not, then you'll need to link the program against the library that contains the definition of Outside_library::my_const . 如果不这样做,那么您需要将程序链接到包含Outside_library::my_const 定义的库。

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

make_unique takes (forwardind) reference of its parameter, and so odr-use it. make_unique接受(forwardind)引用它的参数,所以odr-使用它。

My_class(Outside_library::my_const) only use the value. My_class(Outside_library::my_const)仅使用该值。

One solution is to define the member in a TU: 一种解决方案是在TU中定义成员:

const int Outside_library::my_const;

or using constexpr value (since C++11): 或者使用 constexpr值(从C ++ 11开始):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM