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

时间:2018-01-24 17:38:21

标签: c++ c++14 smart-pointers

当我尝试使用static const初始化unique_ptr时,我会得到一个"未定义的引用"错误。但是,当我new指针使用相同的常量时,符号似乎是神奇地定义的。

这是一个重现错误的简单程序:

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;
}

我使用

编译了程序
g++ main.cpp -std=c++14

并收到以下错误。

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

有人可以帮助我理解为什么在使用new时定义常量,而不是在使用make_unique时定义?

2 个答案:

答案 0 :(得分:4)

C ++有一个称为One-Definition Rule (ODR)的东西:

  

非正式地,如果一个对象的值被读取(除非它是一个编译时常量)或者被写入,它的地址被采用,或者一个引用被绑定到它上面,那么它就被使用了。如果使用引用并且在编译时不知道它的引用,则引用是odr-used;如果对函数进行了函数调用或者对其进行了地址处理,则函数会被使用。如果一个对象,一个引用或一个函数被使用,它的定义必须存在于程序的某个地方;违反此通常是链接时错误。

链接网站提供以下示例:

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

您的显式构造函数调用不会&#34; odr-use&#34; Outside_library::my_const但是对std::make_unique()的调用确实如此。当一个对象使用odr时,它必须只有一个定义(不是声明)。您的示例仅包含声明。再次来自cppreference

  
      
  1. 潜在评估的表达式中的变量x除非满足以下两个条件,否则使用odr:

         
        
    • 将lvalue-to-rvalue转换应用于x会产生一个不会调用非平凡函数的常量表达式
    •   
    • 要么x不是对象(即x是引用),要么x是对象,它是更大表达式e的潜在结果之一,其中更大的表达式是丢弃值表达式还是应用了左值到右值转换
    •   
  2.   

Jarod42建议的解决方案是使用constexpr而不是const(如果您可以控制&#34;外部库&#34;代码)。如果不这样做,那么您需要将程序链接到包含Outside_library::my_const定义的库。

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

答案 1 :(得分:3)

make_unique获取其参数的(forwardind)引用,因此使用它。

My_class(Outside_library::my_const)仅使用该值。

一种解决方案是在TU中定义成员:

const int Outside_library::my_const;

或使用constexpr值(自C ++ 11起):

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

<击>