Link 使用 const char 创建对象时使用 std::make_unique 时出错 *

Link error when using std::make_unique when creating object with const char *

很抱歉没有提供简单的可运行故障代码。该错误是需要大量重构的较大代码库的一部分。

我 运行 遇到一个非常奇怪的 link 我的代码问题,到目前为止我无法解决。 我有一个 class 和 static constexpr const char * 用于一些字符串和本地 std::sunique_ptr。指针指向不同的模板 class,其中包含另一个模板 class (#2).

主要class是这样的(节选):

class Manager {
 public:
  Manager();

  virtual ~Manager();

 private:
  // Topic Constants
  static constexpr const char* kActuatorsCommand = "ActuatorsCommand";
  static constexpr const char* kActuatorsProxy = "ActuatorsProxy";

  std::unique_ptr<DataReader> faults_;
};

所以 DataReader 构造函数有两个 const string & 参数。

如果我将 faults_ 声明为常规旧指针并使用 new 创建它,代码运行并且 links 就好了:DataReader *faults_ = new DataReader<uint32_t>(kActuatorsCommand, kActuatorsProxy).

但是,如果我使用 std::make_unique,link 用户会抱怨说存在对那些 static const char* 字符串的未定义引用,即使它们位于 class.

此外,如果我删除 #2 class 一切 link 都很好。

使用gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0


我知道这可能是一个相当模糊的问题,但希望能找到一些方向。

另外,这个问题可能与类似。但是,就我而言,一切都在一个二进制文件中。


更新:终于找到了如何重现它。

class DataReader {
 public:

  explicit DataReader(const std::string& topic, const std::string& library_name)
      : topic_(topic),
        library_name_(library_name) {
  }

 private:
  const std::string name_;
  const std::string topic_;
  const std::string library_name_;
};


#include <memory>
#include "DataReader.h"

class Manager {
 public:
  Manager();
  virtual ~Manager();

 private:
  // Topic Constants
  static constexpr const char* kActuatorsCommand = "ActuatorsCommand";
  static constexpr const char* kActuatorsProxy = "ActuatorsProxy";

  std::unique_ptr<DataReader> faults_;
};


Manager::Manager() {
    faults_ = std::make_unique<DataReader>(kActuatorsCommand, kActuatorsProxy);
}

Manager::~Manager() {}

使用 -o0 编译时代码无法 link。使用 -03 它 link 没问题。

g++ -O0 -Wall -Wconversion -lstdc++ -pthread -std=c++14 -o ex3 src/ex3.cpp
/tmp/ccJebZ18.o: In function `Manager::Manager()':
ex3.cpp:(.text+0x41): undefined reference to `Manager::kActuatorsProxy'
ex3.cpp:(.text+0x48): undefined reference to `Manager::kActuatorsCommand'
collect2: error: ld returned 1 exit status
Makefile:8: recipe for target 'ex3' failed

我觉得跟内联有关系

A constexpr specifier used in a function or static member variable (since C++17) declaration implies inline

当您使用 -O3-O0 -std=c++17 编译代码时,静态变量可能是内联的,从而避免了未定义的引用。

我做了一些挖掘并发现:

You can take the address of a static member if (and only if) it has an out-of-class definition

来自 Bjarne Stroustrup's C++ faq。 将以下代码添加到 class 主体之外的示例,使其使用 -std=c++14:

进行编译
constexpr const char* Manager::kActuatorsCommand;
constexpr const char* Manager::kActuatorsProxy;