简体   繁体   中英

Ensure safety while using CRTP

Consider following snippet of code making using of CRTP

#include <iostream>

struct Alone
{
    Alone() { std::cout << "Alone constructor called" << std::endl; }
    int me {10};
};

struct Dependant
{
    explicit Dependant(const Alone& alone)
        : ref_alone(alone)
    { std::cout << "Dependant called with alone's me = " << alone.me << std::endl; }
    const Alone& ref_alone;
    void print() { std::cout << ref_alone.me << std::endl; }
};

template <typename D>
struct Base
{
    Base() { std::cout << "Base constructor called" << std::endl; }

    D* getDerived() { return static_cast<D*>(this); }
    Dependant f { getDerived()->alone };
    void print() { f.print(); }
};

struct Derived : Base <Derived>
{
    Derived() { std::cout << "Derived constructor called "  << std::endl; }
    Alone alone {};
    void print() { Base::print(); };
};

int main()
{
    Derived d;
    d.print();
}

original link http://coliru.stacked-crooked.com/a/79f8ba2d9c38b965

I have a basic question first

  • How does memory allocation happen when using inheritance? I know the constructors are called from Base to Derived, but it seems that when I do

    Derived d;

    memory equivalent to sizeof(D) is allocated, and then constructors are called. Is my understanding correct here? (This would explain printing uninitialised member)

  • Considering the above example in mind, would you suggest/recommend any best practices when it comes to CRTP?

memory equivalent to sizeof(D) is allocated, and then constructors are called

How else could it possibly work? You can't construct an object in memory that isn't allocated yet. Memory allocation always comes before object construction.

Considering the above example in mind, would you suggest/recommend any best practices when it comes to CRTP?

The standard practices for the CRTP: don't call into the CRTP in a constructor/destructor. This is also true of virtual functions. Virtuals are dynamic polymorphism, while CRTP is static polymorphism. But they're both using the same basic mechanism: a base class that defines an interface that the derived class must implement.

And just like with virtual functions, trying to call it in constructors/destructors won't do what you mean. The only difference is that with virtual functions, the compiler will actually keep you from getting undefined behavior. Whereas with the CRTP, you just get breakage.

Note that this includes default member initializers, which for the purpose of non-aggregates are just shorthand for constructor initialization lists.

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