84

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

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

通常,如果需要,任何主流编译器都会在调用点替换函数体,因此inline仅仅为函数标记#1并不是真正需要的。

进一步#2说,据我所知,当您将函数声明为static inline函数时,

函数上的static关键字强制inline函数具有内部链接(内联函数具有外部链接)此类函数的每个实例都被视为单独的函数(每个函数的地址不同)并且这些函数的每个实例都有自己的副本静态局部变量和字符串文字(内联函数只有一个副本

因此,这样的功能就像任何其他static功能一样,关键字inline不再重要,它变得多余。

因此,实际上标记一个功能staticinline两者都没有任何用处。它应该是static不是最喜欢的)或inline最喜欢的),
那么,在一个函数上使用staticandinline一起实际上没有用吗?

4

5 回答 5

68

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

忽略与 , 的交互inlinestatic应谨慎使用函数。命名空间范围的static修饰符以前被弃用,取而代之的是未命名的命名空间(C++03 §D.2)。由于某些模糊的原因,我不记得它在 C++11 中已从弃用中删除,但您应该很少需要它。

因此,实际上将函数标记为静态和内联都没有任何用处。它应该是静态的(不是最喜欢的)或内联的(最喜欢的),

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

首选是使用未命名的命名空间,而不是static

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

static inline void worse(); // kludge the linker to allowing duplicates
于 2012-06-04T06:22:26.023 回答
29

静态和内联是正交的(独立的)。静态意味着函数不应该在翻译单元之外可见,内联是对编译器的提示,程序员希望内联这个函数。这两个没有关系。

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

例子:

源1.cpp:

inline int Foo()
{
  return 1;
}

int Bar1()
{
  return Foo();
}

源2.cpp:

inline int Foo()
{
  return 2;
}

int Bar2()
{
  return Foo();
}

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

于 2012-06-04T06:40:47.583 回答
18

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

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

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

于 2013-05-10T02:09:28.397 回答
13

如果您谈论自由功能(namespace范围),那么您的假设是正确的。static inline功能确实没有太大价值。所以static inline只是一个static函数,它自动满足 ODR 并且inline对于 ODR 目的是多余的。

但是,当我们谈论成员方法(class作用域)时,static inline函数确实具有价值。
一旦你将一个class方法声明为inline,它的全部内容必须对所有包含它的翻译单元可见class

请记住,static当涉及到 a 时,关键字具有不同的含义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
}
于 2012-06-04T06:25:03.070 回答
3

我刚刚阅读了 gcc 的手册页,它特别说明了使用带有编译器标志的静态内联。在 flag 的情况下,它内联函数,如果它也是静态的并且在它被调用的每个实例中都内联,那么它会摆脱在创建的目标文件中永远不会使用的函数定义,从而减少生成代码的大小。

于 2015-02-02T09:05:27.097 回答