I see the problem now.
There is a big misunderstanding of when an object destructor is invoked, and what is its relationship with the constructors.
To be saved by heart:
"A destructor can be called only when the object is successfully constructed"
At construction time, if i construct "member1" then "member2" then "member3", or
"member2", then "member1" then "member3",
Or in any other permutation possible.
When the constructor finishs, i will have:
member1, member2, member3 and the instance that contains them, all in their correct places and initialized safe and sound.
At destructor invocation time, the destructor finds all the member subobjects in their correct places and it starts destroying from whatever order the standard wants.
Why? Because the destructor is only available when all the subobjects exist and are in their places.
Does it need to know how the object was constructed? NO
How hard is this to understand?
The only thing that matters to a destructor is that the object finished construction successfully.
Sy Brand !!
Where are you?
-------- Original message --------
From: connor horman via Std-Proposals <email@example.com>
Date: 2/26/22 7:00 PM (GMT+04:00)
Cc: connor horman <firstname.lastname@example.org>
Subject: Re: [std-proposals] Relax condition for potentially invoked destructor in constructor
The current implementation which assumes that the member initialization list calls the member subobjects constructors in order of declaration, otherwise garbage is produced.
This is disaster!
It's not so much an assumption as a definition, in order to keep things simple and efficient. The "disaster" is quite easily averted by "-Wall -Werror". As I said earlier, all major compilers will tell you if your initializer list is in a different order than declaration order.
Where is the difficulty to implement it the following way:
1- At compile time, scan the constructor member initialization list.
2- create a dependency graph.
3- make sure that class subobjects are initialized first in their order of inheritance.
4- generate code for the constructor under compilation, which will call the member subobjects constructors in different order than their declaration order in the class, as per the user wish.
Isn't more intuitive?
You keep hand-waving away the problem of the destructor possibly being defined in a separate translation unit that cannot see the definition of the constructor. You also hand-wave away the possibility of having two constructors that end up with different initialization orders. In that case you need to record, at run-time, which constructor was used for a specific instance, so the destructor knows which order to destroy its subobjects in. Doing either is a net negative in my book.
Indeed. An easy case would have an inline (probably defined as default) destructor, and a non-trivial out-of-line constructor? What order does the defaulted destructor use to destroy the elements? Does it different between translation units (ODR)? Is it the same (potentially no longer reverse order of construction)? A combination of both is most likely under the above proposal, so you've not only broken the guarantee of Reverse-order of construction always, but you've also made the program IFNDR. In order for the proposal to actually be functionally viable it requires that the definition of every constructor be available in the translation unit that defines the out-of-line destructor or in every translation unit that contains the definition of the inline destructor, *and* every constructor must use the same initialization order. And what about default-initialized fields/fields with default-member-initializers? What order do they get initialized in? What happens with some constructors use explicit initializers for them, and others don't? The rule seems simple in theory, but in C++ it's far too complex, makes far too many trade-offs, and arguably comes with non-zero cost.
You could invent a build system that guarantees that all translation units containing constructors are compiled first, then communicate which order they ended up deciding to initialize subobjects in, and then feed this information into all the translation units that contain destructors. I hope you see the difficulty and complexity of trying to do that (for virtually zero benefit).
As a program writer, i will be free to not watch in which order i initialize my member objects, when writing my constructor.
It is so flexible and saves the day.
Passing "-Wall -Werror" to your compiler also saves the day, and is simpler.
An object constructor is sensible piece of code, making it non-intuitive could lead to disaster.
Just imagine this scenario:
" some developer want to write the constructor of a defibrillator, then by mistake he didn't respect the order of initialization of just one member object, now his defibrillator instead of starting at ZERO volts power, it starts at a random value.
Two consequences, either his code damages the machine, or kills the patient"
That's why you would be required (by law most likely) to pass "-Wall -Werror" to your compiler when building medical devices.
Std-Proposals mailing list