0

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.

6
  • 5
    You can't put a B object in an array of As. Commented Jun 8, 2024 at 18:24
  • 1
    "but manipulate it differently in their constructor" -- This is a weak reason for defining a derived class, and by insisting that this approach (X) be used, you eliminate potential solutions to your original problem (Y). Commented Jun 8, 2024 at 23:06
  • Also known as the XY Problem Commented Jun 8, 2024 at 23:18
  • @JaMiT Actually I'm not 'insisting' on it. I just got tunnel vision on trying to do it with inheritance and needed to step back and see the bigger picture, that there are other ways of achieving the desired result. Commented Jun 8, 2024 at 23:50
  • 1
    @poby "Actually I'm not 'insisting' on it." -- I'll grant that my phrasing is somewhat exaggerated, but it's still true that the question establishes the inheritance as a given, which limits the direction answers can take. Keep it in mind, but don't worry too much about it -- tunnel vision affects most people at some point. Commented Jun 9, 2024 at 0:15

1 Answer 1

4

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>() };
Sign up to request clarification or add additional context in comments.

3 Comments

Yeah I get it. But I want to have derived objects with constructors that manipulate the base object data in custom ways. This is why B contains no actual data. A has all the data I need, for the derived object. There are no errors if I try to put B into A so it is at least allowed, and it does actually work. It just annoys me that the destructors are being called which is wasteful.
If your B only "[manipulates] the base object data in custom ways" this sounds like you'd be better served with builder functions than inheritance.
Thanks @StephenNewell! Your answer gave me the hint I needed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.