简体   繁体   English

GTP中的CRTP与devirtualization标志

[英]CRTP vs devirtualization flag in GCC

I'm starting to study the CRTP idiom, and I've noticed that GCC has a fdevirtualize flag that should allow to transform when possible vtable calls to direct calls. 我开始研究CRTP习语,我注意到GCC有一个fdevirtualize标志,应该允许在可能的vtable调用直接调用时进行转换。

While the CRTP can be applied with any (C++ compliant) compiler, if I want to develop only with gcc, can I avoid CRTP idiom leaving to gcc the devirtualization process or it's always better to use it when possibile in order to use static polymorphism in order to avoid virtual function calls? 虽然CRTP可以应用于任何(C ++兼容)编译器,但如果我只想用gcc开发,我可以避免CRTP习惯用于将gcc作为虚拟化过程,或者在使用静态多态性时最好使用它。为了避免虚函数调用?

Devirtualization might help or not, depending on whether the compiler inlines your stuff. Devirtualization可能有用与否,具体取决于编译器是否内联您的内容。

Note that CRTP is usually used to implement mixins and the template method pattern, eg like this: 请注意,CRTP通常用于实现mixins和模板方法模式,例如:

template <typename T, typename Derived>
class pointer_base {
  const Derived& self() const { return static_cast<const Derived&>(*this); }
public:
  T& operator *() const { return *self().get(); }
  T* operator ->() const { return self().get(); }
};

template <typename T>
class smart_pointer : public pointer_base<T, smart_pointer<T>> {
public:
  T* get() const;
};

And the virtual call form: 而虚拟通话形式:

template <typename T>
class pointer_base {
protected:
  ~pointer_base() = default;
public:
  virtual T* get() const = 0;
  T& operator *() const { return *get(); }
  T* operator ->() const { return get(); }
};

template <typename T>
class smart_pointer : public pointer_base<T> {
public:
  T* get() const override;
};

Usage in either case is 两种情况下的用法都是

smart_pointer<int> p(new int);
*p = 42;

Note that there could be multiple different smart pointer classes. 请注意,可能有多个不同的智能指针类。 In the virtual function version, they all derive from the same pointer_base. 在虚函数版本中,它们都来自相同的pointer_base。 This means that there is one version of the base function to be shared among all of these. 这意味着在所有这些中共享基本函数的一个版本。 And if that's the case, devirtualization can't work. 如果是这种情况,那么虚拟化就无法发挥作用。

It will only work if the function in question is inlined into the caller, because then the compiler can specialize the code to the particular concrete smart pointer type. 它只有在有问题的函数内联到调用者中时才有效,因为编译器可以将代码专门化为特定的具体智能指针类型。

Of course, with the helpers so small, chances that they get inlined are high. 当然,由于佣工如此之小,他们内联的可能性很高。 On the other hand, you now have a pointer_base class that clients see and might be tempted to use. 另一方面,您现在有一个客户端看到并可能想要使用的pointer_base类。 You could derive privately from the base, but then you have to add using declarations for all members you want to expose in every derived class. 您可以从基础私有派生,但是您必须为每个派生类中要公开的所有成员添加声明。 With classes like pointer_base, which consists of lots (2 in my case, but there really should be a boolean conversion too) of small functions, that's annoying. 对于像pointer_base这样的类,它包含很多(在我的情况下为2,但确实应该有一个布尔转换)的小函数,这很烦人。 But then, so is the syntactic clutter of CRTP. 但是,CRTP的语法混乱也是如此。 It comes down to a matter of taste, I think. 我想,这归结为品味问题。

When you have just one, big template method, the compiler won't inline it most likely. 当你只有一个大模板方法时,编译器最不会内联它。 In that case, it can't devirtualize. 在这种情况下,它无法虚拟化。 But the CRTP has its own drawback: the method is duplicated for every instantiation of the base, whether you want it or not. 但CRTP有其自身的缺点:无论您是否需要,该方法都会在基础的每个实例化中重复。 This can lead to code bloat. 这可能会导致代码膨胀。

So it ultimately comes down to the usual question for templates vs virtual functions: specialized code with its associated code size increase, or the performance penalty of virtual calls and the inlining barrier they put up. 因此,它最终归结为模板与虚函数的常见问题:专用代码及其相关代码大小的增加,或虚拟调用的性能损失以及它们提出的内联障碍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM