简体   繁体   English

内联函数和一个定义规则

[英]inline functions and the one definition rule

inline functions provide something of a weakening of the one definition rule -- multiple definitions are allowed, albeit with some restrictions. inline函数提供了一个定义规则的弱化 - 允许多个定义,尽管有一些限制。 One wording I found online is 我在网上发现的一个措辞是

The requirements are that each definition should be the same, meaning it should consist of the same tokens and refer to the same items. 要求是每个定义应该相同,这意味着它应该由相同的标记组成并引用相同的项目。

though I admit that I don't know if that's definitive. 虽然我承认我不知道这是否是确定的。 I'm also not sure how strict it is. 我也不确定它有多严格。

I'm considering cases in which I create headers with class definitions and/or inline functions that I want to be #include -able whether one is compiling in C++03, C++11, or even some later standard. 我正在考虑使用class定义和/或inline函数创建标题的情况,我希望它是#include -able,无论是在C ++ 03,C ++ 11中编译,还是在以后的某些标准中编译。 It would be natural to use the __cplusplus macro to conditionally change the code, but will the ODR come into play? 使用__cplusplus宏来有条件地更改代码是很自然的,但是ODR会发挥作用吗? For example, it seems reasonable to conditionally : 例如, 条件似乎是合理的:

  • provide a nested typedef . 提供嵌套的typedef
  • provide a nested class . 提供一个嵌套class
  • provide move-related functions. 提供与移动相关的功能。
  • mark a function throw() or noexcept . 标记函数throw()noexcept (This is particularly important since every destructor picks up an implicit noexcept in C++11.) (这一点特别重要,因为每个析构函数noexcept在C ++ 11中获取一个隐式的noexcept 。)
  • mark a function constexpr . 标记功能constexpr
  • mark a function with override and/or final . override和/或final标记一个函数。
  • mark a function [[noreturn]] and/or [[nodiscard]] . 标记函数[[noreturn]]和/或[[nodiscard]]
  • mark a parameter [[maybe_unused]] . 标记参数[[maybe_unused]]
  • use [[fallthrough]] within a function body. 在函数体中使用[[fallthrough]]

but which of these -- if any -- are actually allowed if one wants to enable libraries that #include such headers to be compiled under different standards and still be safely used together? 但是,如果有人想要启用#include这些头文件库以便在不同标准下编译并仍然可以安全地一起使用,那么这些中的哪一个 - 如果有的话 - 实际上是允许的?

In general, you can't do any of this stuff safely. 一般来说,你不能安全地做这些事情。 There's only two ways to safely use say two definitions of a class. 安全使用说两种类的定义只有两种方法。 Trivially you can simply have two separate processes compiled differently that communicate via eg shared memory. 平凡的是,你可以简单地编译两个不同的进程,通过例如共享内存进行通信。 Less trivially, you can use two libraries that define the same symbol A in two different way if: 不那么简单,如果出现以下情况,您可以使用两个以两种不同方式定义相同符号A的库:

  • the symbol A is only an implementation detail of the library; 符号A只是库的实现细节; it cannot be provided by the library nor appear in any interfaces 它不能由库提供,也不能出现在任何接口中
  • Along these lines, none of the library's header files should transitively include A's header. 沿着这些方向,库的头文件都不应该传递包含A的头。 So client translation units will not receive any definition of A from the library. 因此,客户端翻译单元将不会从库中接收任何A的定义。
  • the visibility of the symbol A must be marked private/hidden. 符号A的可见性必须标记为私有/隐藏。

If you do all that, then A is truly an implementation detail of the library, and you can use multiple libraries that define A differently. 如果你做了所有这些,那么A确实是库的实现细节,你可以使用多个不同定义A的库。 If any of these is not satisfied, then you can't guarantee that any of the above will work (though some will). 如果其中任何一个不满意,那么你不能保证上述任何一个都可以工作(虽然有些人会这样做)。

One of the most surprising outcomes for those not familiar with the linker, is that if lib1 and lib2 both use symbol A, even if they stop any leakage through the headers, if the visibility of A is public then a single definition of A will be used across both libraries. 对于不熟悉链接器的人来说,最令人惊讶的结果之一是,如果lib1和lib2都使用符号A,即使它们阻止通过头部的任何泄漏,如果A的可见性是公开的,那么A的单个定义将是用于两个库。 So either lib2 will use lib1's definition, or vice versa. 因此lib2将使用lib1的定义,反之亦然。 This can rather easily lead to UB. 这很容易导致UB。

On *nix systems, public visibilility is the default so you will need to be sure to go out of your way to hide the symbol, which is a bit arcane. 在* nix系统上,公共可见性是默认设置,因此您需要确保隐藏符号,这有点神秘。

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

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