Daniel Langr
Daniel Langr

Reputation: 23527

Using `this` as a pointer to derived class in a base class in CRTP

I am trying to use CRTP to register all live (created but not yet destroyed) instances of some class. This works for me well:

template <typename T>
class Registrable {
  public:
    void _register(T* p) { instances_.insert(p); }
    void _unregister(T* p) { instances_.erase(instances_.find(p)); }
    static const std::set<T*> & instances() { return instances_; }
  private:
    static std::set<T*> instances_;
};

template <typename T>
std::set<T*> Registrable<T>::instances_;

class Class : private Registrable<Class> {
  public:
    using Registrable<Class>::instances;
    Class() { _register(this); }
    Class(const Class &) { _register(this); }
    Class(Class &&) { _register(this); }
    ~Class() { _unregister(this); }
    void function() { }
};

int main() {
  Class c;
  auto upc = std::make_unique<Class>(c);
  std::vector<Class> vc(5);
  for (auto i : Class::instances())
      i->function();
}

EDITED:

Better would be not to care about registering and unregistering of instances in derived classes. Solution according to @Jean-BaptisteYunès and @Aconcagua:

template <typename T>
class Registrable {
  public:
    static const std::set<T*> & instances() { return instances_; }
  protected:
    Registrable() { instances_.insert(static_cast<T*>(this)); }
    Registrable(const Registrable &) : Registrable() { }
    Registrable(Registrable &&) : Registrable() { }
    ~Registrable()  { instances_.erase(instances_.find(static_cast<T*>(this))); }
  private:
    static std::set<T*> instances_;
};

...

class Class : public Registrable<Class> { ... }

However, I am also not sure whether this type of casting is safe. Especially, if Class would additionally derive from another class via multiple inheritance.

The answer of @amc176 claims, that I can assume that the cast will be successful, but I would prefer to be sure. According to @Aconcagua's comment, I can be sure, just it's not in the answer.

Upvotes: 3

Views: 522

Answers (1)

amc176
amc176

Reputation: 1544

static_cast makes no runtime checks to ensure the cast is completely safe. Anyway, as you know the type T will be a derived class of Registrable<T>, you can assume the cast will be successful.

In fact, in cppreference it's mentioned that this cast is typically used when applying CRTP (referred as static polymorphism in the link).

Upvotes: 2

Related Questions