简体   繁体   中英

C++ Initialize std::vector<std::unique_ptr<Base>> in derived classes

I have a polymorphic base class storing a std::vector<std::unique_ptr<Base>> . I would like to initialize this vector in the derived classes. The sizes of these vectors are known at compile time and do not change after construction. In my current solution I have a pure virtual function initialize() which is overriden in each Derived:

class Base {
public:
    virtual void Initialize() = 0;
    virtual ~Base() = default;
protected:
    Base(std::size_t count) : m_data(count) {}
    std::vector<std::unique_ptr<Base>> m_data;
};

class Derived1 : public Base {
public:
    Derived1() : Base{ 8 } {}
    void initialize() override {
        m_data[0] = std::make_unique<Derived1>();
        // ...
        m_data[7] = std::make_unique<Derived1>();
    };
};

class Derived2 : public Base {
public:
    Derived2() : Base{ 24 } {}
    void initialize() override {
        m_data[0] = std::make_unique<Derived2>();
        // ...
        m_data[23] = std::make_unique<Derived2>();
    };
};

However, I am not pleased with this solution; Partly because of the use of a virtual function and the redundancy of
m_data[0] = ...; ... m_data[N-1] = ... m_data[0] = ...; ... m_data[N-1] = ... .
I would like to assign m_data like this:

m_data = {
    std::make_unique<Derived1>(),
    // ...
    std::make_unique<Derived1>()
}

which does not work because of std::unique_ptr s deleted copy ctor.

Here is a more realistic sample of my code

What is the best way to initialize the vector in the derived classes? I am using C++17.

However, I am not pleased with this solution; Partly because of the use of a virtual function

If the virtual function is a problem, then make it non-virtual.

and the redundancy

You can simply use a loop to get rid of the repeated assignments:

for (auto& ptr : m_data)
    ptr = std::make_unique<Derived1>();

To avoid redundancy from having identical code for each type, there is tool for that in C++, templates:

template<class D, std::size_t N>
struct BaseT : Base {
    BaseT() : Base{N} {}
    void Initialize() override {
        for (auto& ptr : m_data)
            ptr = std::make_unique<D>();
    };
};

struct Derived1 : BaseT<Derived1, 8> {};
struct Derived2 : BaseT<Derived2, 24> {};

In this case, the template argument is the derived type. There is a name for such idiom: Curiously Recurring Template Pattern.

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