简体   繁体   中英

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.

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?

Devirtualization might help or not, depending on whether the compiler inlines your stuff.

Note that CRTP is usually used to implement mixins and the template method pattern, eg like this:

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. 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. 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. But then, so is the syntactic clutter of 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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