惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

核桃的炼金工坊

2023 韩国游记 C++23: Flat Containers Deducing This Stateful Metaprogramming 推し、燃ゆ Customization Point Object 2020 总结 搞了个 C++ 构建系统 软件设计哲学(NOTE) Paxos Note 关于 cpp 可见性的黑魔法后门 一个关于 private member function detect 的 SFINAE 模板 User-defined conversion and Copy elision VIM and Latex Interface in C++ Compile Time Reflection in C++11 C++11内存模型 在C++17中的部分新特性 Const Reference of Pointer
Compare Between CRTP and Virtual
Hawtian Wang · 2018-10-16 · via 核桃的炼金工坊

我们平时都会使用虚函数来实现 C++ 里的运行时的多态,但是虚函数会带来很多性能上面的问题:

  1. 虚函数的调用需要额外的寻址
  2. 虚函数不能被 inline,当使用比较小的虚函数的时候会带来很严重的性能负担
  3. 需要在每个对象中维护一个额外的虚函数表

但是在有些情况下,我们就可以用一些静态的类型分发策略来带来一些性能上面的好处。

struct VirtualInterface {
  virtual void Skip(uint32_t steps) = 0;
};

struct VirtualImpl : public VirtualInterface {
  uint32_t index_;

  void Skip(uint32_t steps) override { index_ += steps; index_ %= INT_MAX; }
};

void VirtualRun(VirtualInterface* interface) {
  for (auto i = 0; i < N; i++) {
    for (auto j = 0; j < i; j++) {
      interface->Skip(j);
    }
  }
}

这里有一个很简单的例子,我们搞了一个简单的计数类来模拟这个过程。首先使用虚函数的方法去实现这个。在开了O2的情况下,运行了 3260628226 ns。

然后我们使用 CRTP 来实现:

template <typename Impl>
struct CrtpInterface {
  void Skip(uint32_t steps) { static_cast<Impl*>(this)->Skip(steps); }
};

struct CrtpImpl : public CrtpInterface<CrtpImpl> {
  void Skip(uint32_t steps) {
    index_ += steps;
    index_ %= INT_MAX;
  }

  uint32_t index_ = 0;
};

template <typename T>
void CrtpRun(CrtpInterface<T>* interface) {
  for (auto i = 0; i < N; i++) {
    for (auto j = 0; j < i; j++) {
      interface->Skip(j);
    }
  }
}

同样运行我们的代码, 29934437 ns。 显然在省去了查虚函数表,并且可以inline的情况下,程序有了更好的表现。

在具体的实现方式上,参考上面的实现就可以了…