c++stdarray

How to initialize std::array with derived object without copying?


If I have these objects:

struct A
{
    int aa{};

    A() {};    
    ~A()
    {
        OutputDebugStringA("~A\n");
    }
};

struct B : public A
{
    B() {};
    ~B()
    {
        OutputDebugStringA("~B\n");
    }
}; 

I can aggregate initialize a std::array of A or B without copying:

std::array<A, 1> arr0{ A{} };
std::array<B, 1> arr1{ B{} };

BUT if I try to creat a std::array of the base class and initialize it with the derived class:

std::array<A, 1> arr0{ B{} };

It works without error however, there is copying going on as the destructors are being called. So my question is why? And is there any reasonable way to structure it to avoid copying?

The reason I am asking is that I have a base object that contains data and I have a large number of derived objects that only have the data inherited from the base, but manipulate it differently in their constructor.

The program works without errors. I just don't like the waste of objects being destroyed. I'm guessing it isn't possible with aggregate initialization. If that's the case I can either ignore the waste (viable option), or structure it differently which would also make it a little wordier.

All the objects, size and types are known at compile time.


Solution

  • It works without error however, there is copying going on as the destructors are being called. So my question is why?

    You array holds actual A instances. You can't store a B object into an A instance. The compiler will slice the B object and copy just the A portion of the object into the A instance. So, in your example, the B object is temporary and gets destroyed after its A base is copied into the array.

    And is there any reasonable way to structure it to avoid copying?

    No. If you need an array of As to hold B objects, you have to use A* pointers instead, for example:

    std::array<B, 1> arr0{ B{} };
    std::array<A*, 1> arr1{ &arr0[0] };
    

    Or:

    std::array<std::unique_ptr<A>, 1> arr0{ std::make_unique<B>() };