C++ 使用不同版本的仅标题库是否会导致UB
假设我有一个库C++ 使用不同版本的仅标题库是否会导致UB,c++,static-libraries,static-linking,C++,Static Libraries,Static Linking,假设我有一个库somelib.a,它由包管理器以二进制形式分发。并且该库使用仅标题库anotherlib.hpp 如果我现在将我的程序链接到somelib.a,并且使用anotherlib.hpp但版本不同,那么如果somelib.a在其include标题中使用anotherlib.hpp的一部分,这可能会导致UB 但是如果somelib.a仅在其cpp文件中引用/使用anotherlib.hpp,会发生什么情况(因此我不知道它是否使用了它们)?我的应用程序和somelib.a之间的链接步骤是否
somelib.a
,它由包管理器以二进制形式分发。并且该库使用仅标题库anotherlib.hpp
如果我现在将我的程序链接到somelib.a
,并且使用anotherlib.hpp
但版本不同,那么如果somelib.a
在其include
标题中使用anotherlib.hpp
的一部分,这可能会导致UB
但是如果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;
}
}
#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.< /P> 实际上,这意味着除非标题库的两个版本之间的更改非常有限,否则您将拥有UB。 例如,如果唯一的更改是空白更改、注释或添加新符号,则不会有未定义的行为。但是,如果现有函数中的一行代码被更改,那么它就是UB 从: 6.2一条定义规则 [……] 类别类型可以有多个定义(第12条), 枚举类型(10.2),带外部链接的内联函数 (10.1.6),带外部连杆的内联变量(10.1.6),等级 模板(第17条),非静态功能模板(17.5.6),静态 类模板的数据成员(17.5.1.3),类的成员函数 模板(17.5.1.1),或一些 如果每个定义出现在不同的翻译单元中,并且定义满足 以下要求 给定在多个翻译中定义的名为D的实体 单位,那么
- D的每个定义应包含相同的定义 令牌序列;及
- 在D的每个定义中,对应
根据6.4查找的名称应指定义的实体
在D的定义范围内,或指同一实体
重载分辨率(16.3)和部分模板匹配后
专业化(17.8.3),但名称可参考(6.2.1)
- 一个非易失性常量对象,如果对象
- 在D的所有定义中具有相同的文字类型, (6.2.1.2)
- 使用常量表达式(8.20)初始化
- odr是否用于D的任何定义,以及
- 在D的所有定义中具有相同的值
- 使用常量表达式初始化的具有内部链接或无链接的引用 这样,引用在所有定义中都引用同一实体 D;及(6.3)
- 一个非易失性常量对象,如果对象
- 在D的每个定义中,对应的实体 应具有相同的语言链接;及
- 在每个定义中 对于D,引用的重载运算符,隐式调用 转换函数、构造函数、运算符新函数和 操作员删除功能,应指相同的功能,或 D定义中定义的函数;及
- 在每个定义中 D、 (隐式或显式)函数调用使用的默认参数 被视为其标记序列出现在的定义中 D也就是说,默认参数取决于需求 如本段所述(如果默认参数 具有默认参数的子表达式,此要求适用 递归地)
- 如果D是一个隐式声明了 构造函数(15.1),就好像构造函数是隐式定义的 在每个使用odr的翻译单元中,以及 每个翻译单元中的定义应调用相同的构造函数 对于D的子对象
这取决于库和编译器,如果库版本不兼容,那么是的,它将无法工作。提供@AlanBirtles是的,这是关于潜在的不兼容库版本。我更新了这个问题,让它包含一个类似mcve的东西,至少希望它能更清楚地说明我的问题。因此,如果一个库是作为静态库分发的,那么它必须用它们的版本记录所有库(包括仅在内部使用的头库),以便