4

考虑下一个简单的例子:

标题:

// a.hpp
#ifndef A_HPP
#define A_HPP
#include <memory>

class A
{
 public:
  A();

  int foo();

 private:
  struct Imp;
  std::auto_ptr< Imp > pimpl;
};

#endif // A_HPP

实施:

// a.cpp
#include "a.hpp"

struct A::Imp
{
 int foo()
 {
  // do something and return the result
 }
};

A::A() : pimpl( new Imp )
{}
int A::foo()
{
  return pimpl->foo();
}

主要的 :

// main.cpp
#include "header.hpp"
int main()
{
  A a;
  return a.foo();
}

问题是:
该方法A::Imp::foo会被内联到A::foo吗?
它是否取决于该方法中的实现?

PS我正在使用gcc(如果重要的话是4.3.0)。

编辑

我想我解释得不是很好。我的真正意思是这个。如果我使用最大优化级别,是// do something and return the result要放在A::foo()or中A::Imp::foo()吗?
没有优化,我看到这还没有完成(the pimpl->foo()仍然被调用)。

我知道 A::foo() 永远不会在 main() 中内联,但这不是我要问的。

4

2 回答 2

10

所有内联都依赖于实现。如果这对您很重要,请查看发出的汇编代码。

于 2011-06-06T11:19:36.247 回答
10

Herb Sutter 曾经写过一篇关于内联的精彩文章。

要问的第一个问题是:什么时候可以进行内联?

在 C++ 中:

  • 它可能发生在编译阶段
  • 它可能发生在链接阶段(LTO:链接时间优化)

两次,机制是相似的:如果编译器/链接器知道方法的实现,它可能决定复制/粘贴实现来代替发出调用。这个决定是基于复杂的启发式的,我只知道它们存在,而不知道它们是关于什么的。

因此,关键点是对实现位的了解。

  • 对于编译器:这意味着在同一个翻译单元中定义
  • 对于链接器:这意味着在要链接的翻译单元之一中定义,或者在将链接到的静态库中定义...如果方法驻留在 DLL 中,它将不会被优化

所以在这里:是的,调用pimpl->foo()可能内联在A::foo. 这将取决于编译器编译选项。

对于 gcc/clang,如果A::Impl::foo足够小,可以从 O1 开始优化(除非你通过-fno-inline)。

于 2011-06-06T11:59:24.997 回答