假设我有一个库 somelib.a ,它由包管理器以二进制形式分发。这个库使用了只有头文件的库 anotherlib.hpp

如果我现在将我的程序链接到 somelib.a ,并且还使用 anotherlib.hpp 但使用不同的版本,那么这可能会导致 UB,如果 somelib.a 在其 anotherlib.hpp header 中使用 include 的一部分。

但是如果 somelib.a 仅在其 cpp 文件中引用/使用 anotherlib.hpp(所以我不知道它使用它们)会发生什么?我的应用程序和 somelib.a 之间的链接步骤是否会确保 somelib.a 和我的应用程序都将使用它们自己的 anotherlib.hpp 版本。

我问的原因是,如果我将程序的各个编译单元链接到最终程序,那么链接器会删除重复的符号(取决于它是否是内部链接)。因此,只有头的库通常以可以删除重复符号的方式编写。

一个最小的例子
somelib.a 构建在 nlohmann/json.hpp 版本 3.2 的系统上

somelib/somelib.h

namespace somelib {
  struct config {
    // some members
  };

  config read_configuration(const std::string &path);
}

somelib.cpp
#include <nlohmann/json.hpp>


namespace somelib {
  config read_configuration(const std::string &path)
  {
     nlohmann::json j;
     std::ifstream i(path);

     i >> j;

     config c;

     // populate c based on j

     return c;
  }
}

应用程序构建在另一个系统上,nlohmann/json.hpp 3.5 版和 3.2 和 3.5 不兼容,然后应用程序链接到在 3.2 版系统上构建的 somelib.a
application.cpp
#include <somelib/somelib.h>
#include <nlohmann/json.hpp>
#include <ifstream>

int main() {
   auto c = somelib::read_configuration("config.json");

   nlohmann::json j;
   std::ifstream i("another.json");

   i >> j;

   return 0;
}

最佳答案

使用静态库几乎没有任何区别。

C++ 标准规定,如果 在程序 中有一个内联函数(或类模板,或变量等)的多个定义,并且所有定义都不相同,那么您就有了 UB。

实际上,这意味着除非头库的 2 个版本之间的更改非常有限,否则您将拥有 UB。
例如,如果唯一的更改是空格更改、注释或添加新符号,那么您将不会有未定义的行为。但是,如果现有函数中的一行代码发生了更改,那么它就是 UB。

C++17 final working draft (n4659.pdf) :

关于c++ - 使用不同版本的仅 header 库是否会导致 UB,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55138082/

10-11 18:46