静态vs内联函数在头文件中实现

时间:2014-02-28 18:21:30

标签: c++

我在C ++中对inline的看法是用于链接/作用域。我把它放在同一个篮子里,externstatic用于全局对象。

通常,对于在头文件中实现的函数,我的首选解决方案是将其设置为静态:

// In Foo.h
static void foo()
{
    // Do stuff...
}

但是,我相信这也是有效的,似乎并没有违反ODR:

// In Foo.h
inline void foo()
{
    // Do stuff...
}

两者之间有什么语义差异?另外,我不完全确定C ++标准的哪些区域可以解释确切的差异,或者它是否仅仅是未定义的,并且差异在于实现。

4 个答案:

答案 0 :(得分:17)

inline准确传达了你想要的东西:“请为这个函数抑制ODR(一个定义规则),这样每个翻译单元都可以(并且必须)提供它自己的函数定义副本”。

然后,编译器将内联对函数的调用,或者将来自不同TU的函数定义合并在一起(以便生成的函数在可执行文件中存在一次)。

另一方面,

static告诉编译器在定义它的每个转换单元中生成函数,而不是共享它。因此,您最终会在生成的可执行文件中存在任意数量的技术上独立的函数。

简而言之,如果你使用static,那么在不同的翻译单元中获取函数的地址将返回不同的地址(因为你告诉编译器在每个TU中生成一个函数),但是如果你使用inline,它们会显示相同的地址(因为你定义了一个函数,只是告诉编译器将许多定义合并在一起)。

答案 1 :(得分:6)

主要区别在于函数中的任何静态局部变量 - 如果函数是static,则每个编译单元将拥有自己的静态局部变量副本,这些副本不同于任何其他编译单元。如果函数是inline,则所有编译单元只共享一个(一组)静态本地。

答案 2 :(得分:4)

在许多情况下,您不会注意到差异,因为编程器和链接器现在非常聪明。 但是,内联函数必须表现为 - 如果它是常规函数。 标题中的静态函数将被编译到包含它的每个源文件中 - 因此会有很多副本。

大多数情况下,这并不重要,但它有几种方法。 内联函数有一个地址。 静态函数在每个翻译单元中都有不同的地址。

静态局部变量:对于内联,它们将有一个副本。 对于静态函数,每个包含该函数的翻译单元的每个静态局部变量都有一个唯一的副本。

答案 3 :(得分:1)

似乎没有人提到在C ++中,静态函数是直接调用的函数,而不是在类的实例上调用的函数。换句话说,没有隐式的“ this”指针。如果MyClass类的函数foo是静态的,则说:

MyClass :: foo(); //调用

,而不是: MyClass an_object = new MyClass(); an_object-> foo();