应该永远不会使用静态内联函数吗?

Alo*_*ave 61 c++ static inline

使用inline关键字(第7.1.3/4节)有两个含义:

  1. 提示编译器在调用点处替换函数体优于通常的函数调用机制.
  2. 即使省略内联替换,也遵循内联的其他规则(尤其是一个定义规则).

通常,如果需要的话,那么标记功能的任何主流的编译器会在调用点替代函数体inline仅仅是#1是不是真的需要.

进一步说#2,正如我所知,当你将一个函数声明为static inline函数时,

static对功能关键字强制inline函数有一个内部连接(内联函数具有外部连接)这样的功能中的每一个实例被视为一个单独的功能(各功能的地址是不同的)和这些功能中的每一种情况下都有自己的副本静态局部变量和字符串文字(内联函数只有这些的一个副本)

因此,这样的函数就像任何其他static函数一样,并且关键字inline不再重要,它变得多余.

所以,实际标记一个函数static,inline两者都没用.它应该是static(不是最优选的)还是inline(最优选的),
那么,在功能上使用staticinline一起实际上是无用的吗?

Pot*_*ter 49

你的分析是正确的,但并不一定意味着无用.即使大多数编译器自动执行内联函数(原因#1),最好只声明inline描述意图.

无视相互作用inline,static应谨慎使用功能.static命名空间范围内的修饰符以前不赞成使用未命名的命名空间(C++03§D.2).由于一些不明原因,我不记得它已从C++ 11中的弃用中删除,但你应该很少需要它.

因此,实际上标记一个静态和内联函数都没有用.它应该是静态的(不是最优选的)或内联的(最优选的),

没有偏好的概念.static意味着具有相同签名的不同功能可能存在于不同的.cpp文件(翻译单元)中.inline没有static意味着不同的翻译单元可以定义具有相同定义的相同功能.

什么最好是使用不具名命名空间,而不是static:

namespace {
    inline void better(); // give the function a unique name
}

static inline void worse(); // kludge the linker to allowing duplicates
Run Code Online (Sandbox Code Playgroud)

  • @JohannesSchaub-litb 嗯,它们不一定完全相同。它们在 C++ 内的 TU 之间实现了相同的可见性,但 ABI/二进制格式效果可能不同。`static` 不能保证生成像 `namespace{}` 这样的可见的、唯一的名称。不弃用的原因是什么?是 ADL 名称关联、需要具有语言链接功能还是其他原因?如果是 ADL,这不是通过“内联”命名空间修复的吗? (4认同)
  • @Als:无论它出现在何处,对于维护者*代码来说,它更有用,以便声明代码的预期或假设行为.它对代码的*用户*没有那么有用 - 函数的内联与否应该(理想情况下)不重要. (3认同)
  • 没有一个未命名的命名空间优先于静态的概念.两者都具有相同的效果. (2认同)

Sum*_*uma 24

静态和内联是正交的(独立的).静态意味着函数不应该在转换单元之外可见,内联是程序员想要内联此函数的编译器的提示.那两个没有关系.

static inline当在翻译单元之外不使用内联函数时,使用是有意义的.通过使用它,您可以通过在另一个具有相同名称的转换单元中命名另一个内联函数来防止意外违反ODR规则的情况.

例:

source1.cpp:

inline int Foo()
{
  return 1;
}

int Bar1()
{
  return Foo();
}
Run Code Online (Sandbox Code Playgroud)

source2.cpp:

inline int Foo()
{
  return 2;
}

int Bar2()
{
  return Foo();
}
Run Code Online (Sandbox Code Playgroud)

如果不在Foo上使用静态(或者不使用匿名命名空间,这是大多数C++程序员的首选方式),此示例违反ODR并且结果未定义.您可以使用Visual Studio进行测试,Bar1/Bar2的结果将取决于编译器设置 - 在Debug配置中,Bar1和Bar2将返回相同的值(内联未使用,链接器随机选择一个实现),在Release配置中每个都是将返回预期值.

  • “当内联函数不在翻译单元之外使用时,使用‘静态内联’是有意义的。” `static` 是有意义的,添加 `inline` 是没有意义的。 (4认同)

div*_*ero 13

我可能不完全正确,但据我所知,声明一个函数 static inline是使(或允许)编译器生成机器代码的唯一方法,其中函数实际上根本没有在编译代码中定义,并且所有你所拥有的是将声明的函数直接替换为一系列指令,就像它只是一个常规的过程体,在源代码中相对于该函数定义的过程调用的机器代码中没有跟踪.

也就是说,只有static inline你可以真正替代宏的使用,inline本身是不够的.

一个简单的Google搜索"静态内联"将向您展示讨论它的编译器文档页面.我想这应该足以回答你的问题了,并说"不,它实际上没用".以下是讨论使用的网站的一个示例inline,特别是static inline http://www.greenend.org.uk/rjk/tech/inline.html

  • 有趣的是,在[linux内核样式指南](https://www.kernel.org/doc/Documentation/SubmittingPatches)中特别推荐使用`static inline`作为宏的替代品的建议.("静态内联函数比宏更受欢迎.它们提供类型安全,没有长度限制,没有格式限制,在gcc下它们和宏一样便宜."). (3认同)
  • C 中的 inline 关键字与 C++ 具有不同的语义。在 C 中使用具有外部链接的内联函数更复杂,因为您必须手动选择放置非内联版本的翻译单元/目标文件。我相信使用静态内联的建议是以 C 为中心的,主要是出于方便。据推测,它增加了二进制代码重复的风险 (3认同)

iam*_*ind 10

如果你谈论自由函数(namespace范围),那么你的假设是正确的.static inline功能确实没有多大价值.因此,它static inline只是一个static自动满足ODR 的功能,对于ODR而言inline是多余的.

但是,当我们谈论成员方法(class范围)时,该static inline函数确实具有该值.
一旦你声明一个class方法inline,它的全身就必须对包含它的所有翻译单元可见class.

请记住,static关键字具有不同的含义class.
编辑:您可能知道statica class内部的函数没有内部链接,换句话说,static根据转换(.cpp)单位,类不能具有其方法的不同副本.
但是/ global范围内的自由static函数namespace确实每个翻译单元都有不同的副本.

例如

// file.h
static void foo () {}
struct A {
  static void foo () {}
};

// file1.cpp
#include"file.h"
void x1 ()
{
  foo();  // different function exclusive to file1.cpp
  A::foo();  // same function
}

// file2.cpp
#include"file.h"
void x2 ()
{
  foo();  // different function exclusive to file2.cpp
  A::foo();  // same function
}
Run Code Online (Sandbox Code Playgroud)

  • @Suma,你的意思是,如果你提示`inline`那么MSVS也用`/ Ob1`内联一个递归函数调用(OP中的#1效果)?不可能.可能存在其他这样的情况,其中函数将不被其定义替换(例如,函数体太大并且在各个地方被调用).没有提示的价值."内联"的唯一保证效果是#2(来自OP). (2认同)
  • 使用 /Ob1 inline 是可以内联函数的提示。没有被标记为内联函数永远不会内联。 (2认同)