Re: Is it legal to directly call a constructor?
* James Kanze:
On Apr 28, 2:25 pm, "Alf P. Steinbach" <al...@start.no> wrote:
* goodbye...@gmail.com:
class A {
void f() { this->A::A(); }
};
Let's just put away the logic of the program for a moment.
I'm just wondering whether this syntax is legal in standard
C++ or not.
The above is not valid syntax in standard C++.
But regarding your question which you inconveniently put only
in the subject line, "Is it legal to directly call a
constructor", yes of course it is (regarding a constructor of
a most derived class the only indirect way is via the 'new'
operator), and that's what you do every time you call a
constructor.
It really hinges on what you mean by "direct".
Just the opposite of "indirect". :-)
E.g. that could be debated for the case of a virtual call of an ordinary member
routine, is it direct or indirect? At the source code level it's direct. At the
machine code level it's indirect. Just flinging about the word "direct" would
not be sufficient for that case. One would need to be more specific.
But happily, for a constructor there's no such difference between the source
code level and the machine code level.
For a direct constructor call there are possible extra actions (memory
initializer list argument evaluation, invocations of base and member
constructors) but these actions are part of the called constructor. It's not
like there is some way to call the constructor without getting them, as you can
call a virtual routine non-virtually (machine code direct) or virtually (machine
code indirect). The direct -- implicit or explicit -- constructor call ends
up as a direct machine code call, plain and simple.
For an indirect call, operator new (placement or not!), there's indirection both
at the source code level and the machine code level. At the source code level
constructor arguments are handed to an operator, which will do the calling,
indirect. And at the machine code level some funny stuff is used to forward
those arguments after setting up exception handling (if a scheme is used where
that is necessary, i.e. not address look-up based handling) and after calling
the relevant allocation function, which forwarding constitutes an indirection.
There is no
syntax in C++ which "calls a constructor"; every *syntax* which
results in a constructor call also allocates memory. Formally,
at least---placement new can be used to make the memory
allocation a no-op, of course. (But using placement new isn't
really what I'd call "direct". On the other hand, naming a base
class in a initialization list sure looks like a direct call to
the constructor to me.)
Yes. It is a shame that the syntax of C++ differentiates many cases that really
should have been abstracted (e.g., no common "command" syntactic element, so
semicolons are present in a lot of places to /emulate/ that missing element!),
and fails to differentiate cases that really constitute distinct semantical
categories. I guess that this divide, the lack of a mostly one-to-one mapping
between syntax and semantics, leads to endless confusion for the newbies...
Anyway, his example made it more or less clear: he wants to call
the constructor like you'd call any other member function.
Which doesn't work, of course. Logically, since to call any
other member function (including the destructor), you need an
object, and the only way to get an object is to call the
constructor.
Uh, from a pedantic point of view, no. You don't need an object to call a static
member function. And, still pedantically, it depends on the meaning of the word
"call": for a source code level call that is only evaluated at compile time you
don't need an object; indeed there is no object at compile time. ;-)
[...]
The C++ syntax for calling a constructor on existing storage is the basic
placement new, like, for emulating what you're trying to do above,
#include <new>
...
this->A::~A(); // Must first be destroyed.
Technically, only if it has a non-trivial destructor. (Also,
this->A::~A() is probably not a good idea, since the qualified
id prevents virtual function resolution.
In this case qualified destructor call is IMHO the only reasonable idea, the
least ungood. For it's UB to resurrect the object as an object of different type
if it's accessed as the original type. And so one does, in practice, need to
know the exact most derived type, and that should be expressed in the code.
Although just about
anywhere virtual function resolution would make a difference,
explicit destruction will probably cause other problems as
well.)
::new( this ) A(); // Resurrect.
This is extremely dangerous when you don't know what you're
doing, which you don't when you're enquiring about the syntax.
It's even extremely dangerous when you do think you know what
you're doing, or perhaps especially then! There's very seldom
any reason to do it; if or when you feel that that the above
could be a solution to something, ask about solutions to the
something (they will exist, and they will not include the
above).
Even if you know perfectly what you're doing, it's dangerous,
because the person who ends up maintaining your code may not
realize you're doing it, and make some modification which breaks
it (e.g. by adding something to A::A() which might throw).
Yeah. :-)
Cheers,
- Alf
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!