Topic: C++0x: virtual constructors


Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 14 May 2002 22:42:10 GMT
Raw View
In article <kHYD8.7557$T_.174285@iad-read.news.verio.net>,
xleobx@qmailcomq.com wrote:
>Why require the user to do things by hand when the compiler can do them
>better?

Oh, there might be all sorts of reasons, like difficult to implement in
the compiler, low expected user frequency, not part of any general
paradigm or principle, etc.
>In the existing implementation
>
>new(new_arg) X(ctor_arg) effectively translates into
>X::operator new(new_arg)->X(ctor_arg)
>
>so in will be a natural extension to translate
>new(new_arg) typeid(p)(ctor_arg) into something like
>p->operator new(new_arg)->(*typeid(p).get_ctor<ctor_arg_types>())(ctor_arg)
>
>without requiring the user to do mundane things.

If I was at the helms of designing C++ (which I am not), I would want to
look for examples of good use, or to see such stuff fit into to some
general principle or something.

When building a polymorphic hierarchy, one can let classes have different
allocations, say one for small objects, and another for larger objects.
But that requires only static choice of operator new for each class.

I just say that I do not know of any useful examples, not that there are
no such examples.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 13 May 2002 17:30:32 GMT
Raw View
In article <i7ZC8.7493$T_.170421@iad-read.news.verio.net>,
xleobx@qmailcomq.com wrote:
>> I figure that the allocator is chosen statically by the compiler, and
>
>Yes, it is now, because the class is specified statically. With virtual
>constructors it will not be true anymore.
....
>The type_info class will have to provide ways to call the appropriate
>operator new the same way as it will for the ctor.
...
>Strictly speaking, there is no need for virtual function calls.
>Given "new (a, b, c) typeid(p)(e, f, g);" the compiler will have to
>look at all classes that `p' can represent so that for those classes
>operator new (a, b, c) and ctor arguments (e, f, g) are well-formed,
>then construct a switch. Implementations may vary.

I think that the starting point for C++ would be a statically chosen
"operator new" (i.e., the allocator part). In your example, one would
expect  p  to have a static reference to a base class P, while p in
reality may reference another dynamically chosen class Q, derived from P.

Then the (static) base class P would need to have the right typed
"operator new" allocator function (in your example, the "new (a, b, c)"
part). If one wants to go beyond that, then one can write an allocator
function "operator new" that calls typeid, and from that makes a choice of
allocation. -- I am not sure if there is any need beyond that. (Also,
expressions like "new (a, b, c) typeid(p)(e, f, g)" are going to be
entered statically into the language C++. So the types of (a, b, c) and
(e, f, g) will have a static typing anyway.)

But if one finds there really is a need for a polymorphic "operator new",
in expressions perhaps like
    new(*this) typeid(p)(*this)
so that "operator new" gets the truly polymorphic argument "*this". --
Then one should do as you say, to add some information about that into the
typeid-type_info setup.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: xleobx@qmailcomq.com
Date: Tue, 14 May 2002 17:50:25 GMT
Raw View
Hans Aberg <remove.haberg@matematik.su.se> wrote:

>>Strictly speaking, there is no need for virtual function calls.
>>Given "new (a, b, c) typeid(p)(e, f, g);" the compiler will have to
>>look at all classes that `p' can represent so that for those classes
>>operator new (a, b, c) and ctor arguments (e, f, g) are well-formed,
>>then construct a switch. Implementations may vary.

> I think that the starting point for C++ would be a statically chosen
> "operator new" (i.e., the allocator part). In your example, one would
> expect  p  to have a static reference to a base class P, while p in
> reality may reference another dynamically chosen class Q, derived from P.

> Then the (static) base class P would need to have the right typed
> "operator new" allocator function (in your example, the "new (a, b, c)"
> part). If one wants to go beyond that, then one can write an allocator
> function "operator new" that calls typeid, and from that makes a choice of
> allocation. -- I am not sure if there is any need beyond that. (Also,

Why require the user to do things by hand when the compiler can do them
better?

> expressions like "new (a, b, c) typeid(p)(e, f, g)" are going to be
> entered statically into the language C++. So the types of (a, b, c) and
> (e, f, g) will have a static typing anyway.)

Exactly. And the compiler will only have to pick the operator new and
the constructor only from such Q derived from P for which
new (a, b, c) Q(e, f, g) is well-formed. It will be up to the implementor
whether to inline the code that performs the choice, or to outpine it
in some private member function of some type_info derivate.

> But if one finds there really is a need for a polymorphic "operator new",
> in expressions perhaps like
>     new(*this) typeid(p)(*this)
> so that "operator new" gets the truly polymorphic argument "*this". --
> Then one should do as you say, to add some information about that into the
> typeid-type_info setup.

In the existing implementation

new(new_arg) X(ctor_arg) effectively translates into
X::operator new(new_arg)->X(ctor_arg)

so in will be a natural extension to translate
new(new_arg) typeid(p)(ctor_arg) into something like
p->operator new(new_arg)->(*typeid(p).get_ctor<ctor_arg_types>())(ctor_arg)

without requiring the user to do mundane things.

 Leo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: xleobx@qmailcomq.com
Date: Sat, 11 May 2002 03:24:45 GMT
Raw View
Hans Aberg <remove.haberg@matematik.su.se> wrote:

>>I did not fully understand the question, but do you want to pollute
>>the code space with all possible combinations of operator new(...) and
>>the ctor? operator new needs to be virtualized separately from the ctor.

> I figure that the allocator is chosen statically by the compiler, and

Yes, it is now, because the class is specified statically. With virtual
constructors it will not be true anymore.

> could thus be embedded with the virtual table fuction call. For dynamic
> allocator selections (i.e., a constructor can change it at rumtime), I do
> not know -- I do not think that the C++ supports that now.

> Othewise, I do not see the details of an implementation.

The type_info class will have to provide ways to call the appropriate
operator new the same way as it will for the ctor.

>>What if we have different operator new's for different derived classes?
>>The allocator needs to be virtual as well, so a long-standing axiom
>>that a method cannot be both static and virtual will be abolished.

> So then I think it will merely be embedded with the virtual function call,
> but statically chosen for each constructor by the compiler.

Strictly speaking, there is no need for virtual function calls.
Given "new (a, b, c) typeid(p)(e, f, g);" the compiler will have to
look at all classes that `p' can represent so that for those classes
operator new (a, b, c) and ctor arguments (e, f, g) are well-formed,
then construct a switch. Implementations may vary.

> I think that the focus should be on making this runtime
> environment safe, not worrying overly about overheads. Thus, use
> exceptions that can ensure that the runtime behavior is safe.

I see your point. Indeed, the incremental cost of adding the check is
negligible in this case.

 Leo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: xleobx@qmailcomq.com
Date: Thu, 2 May 2002 20:06:33 GMT
Raw View
Hans Aberg <remove.haberg@matematik.su.se> wrote:

> With respect to a polymorphic class X, one may add the word "virtual" to a
> declared constructor X(A), where A is a valid type argument (i.e., a list
> of valid types). The implementation behavior is to add the corresponding
> function
>     new X(A)
> to the virtual lookup table in a way that it can be accessed via the
> type_info object.

See objection on tying "new" to a ctor. There must be a mechanism
to dissociate the two.

> This function can then be accessed polymorphicly via the typeid function:
> If p is a polymorphic pointer, then typeid(*p)(a), where $a$ is of type A
> (stacially checked by the C++ compiler), will yield that result. If
> addition, if the class indicated by typeid(*p) does not have the
> constructor defined, an exception should be thrown when typeid(*p)(a) is
> being called.

An exception, or simply "undefined behavior" (a la call to pure_virtual())?

 Leo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Fri, 3 May 2002 20:02:46 GMT
Raw View
In article <fKeA8.7312$T_.163590@iad-read.news.verio.net>,
xleobx@qmailcomq.com wrote:
>> With respect to a polymorphic class X, one may add the word "virtual" to a
>> declared constructor X(A), where A is a valid type argument (i.e., a list
>> of valid types). The implementation behavior is to add the corresponding
>> function
>>     new X(A)
>> to the virtual lookup table in a way that it can be accessed via the
>> type_info object.
>
>See objection on tying "new" to a ctor.

What's the reference you have in your mind here?

> There must be a mechanism
>to dissociate the two.

I just outlined the general idea -- the main (user) point is that after
the indicated allocator (operator new) is invoked, the dynamically chosen
constructor is invoked.

>> This function can then be accessed polymorphicly via the typeid function:
>> If p is a polymorphic pointer, then typeid(*p)(a), where $a$ is of type A
>> (stacially checked by the C++ compiler), will yield that result. If
>> addition, if the class indicated by typeid(*p) does not have the
>> constructor defined, an exception should be thrown when typeid(*p)(a) is
>> being called.
>
>An exception, or simply "undefined behavior" (a la call to pure_virtual())?

One would expect an exception so that the runtime system can properly
handle it. For example, not all objects are clonable, but there is no way
to prevent a runtime request for cloning an unclonable object. Then, if
the runtime system should not break, there should be a way to handle that,
not merely "undefined behavior". "Undefined behavior" is suitable in
situations where runtime breaks can be avoided by a static analysis, not
otherwise.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: xleobx@qmailcomq.com
Date: Mon, 6 May 2002 07:53:04 GMT
Raw View
Hans Aberg <remove.haberg@matematik.su.se> wrote:
>>>     new X(A)
>>> to the virtual lookup table in a way that it can be accessed via the
>>> type_info object.
>>
>>See objection on tying "new" to a ctor.

> What's the reference you have in your mind here?

I did not fully understand the question, but do you want to pollute
the code space with all possible combinations of operator new(...) and
the ctor? operator new needs to be virtualized separately from the ctor.

> I just outlined the general idea -- the main (user) point is that after
> the indicated allocator (operator new) is invoked, the dynamically chosen

What if we have different operator new's for different derived classes?
The allocator needs to be virtual as well, so a long-standing axiom
that a method cannot be both static and virtual will be abolished.

> constructor is invoked.

>>> This function can then be accessed polymorphicly via the typeid function:
>>> If p is a polymorphic pointer, then typeid(*p)(a), where $a$ is of type A
>>> (stacially checked by the C++ compiler), will yield that result. If
>>> addition, if the class indicated by typeid(*p) does not have the
>>> constructor defined, an exception should be thrown when typeid(*p)(a) is
>>> being called.
>>
>>An exception, or simply "undefined behavior" (a la call to pure_virtual())?

> One would expect an exception so that the runtime system can properly
> handle it. For example, not all objects are clonable, but there is no way
> to prevent a runtime request for cloning an unclonable object. Then, if
> the runtime system should not break, there should be a way to handle that,
> not merely "undefined behavior". "Undefined behavior" is suitable in
> situations where runtime breaks can be avoided by a static analysis, not
> otherwise.

Are you saying that runtime breaks due to object lifetime (see 3.8,
it specifies undefined behavior left and right) can be avoided by static
analysis? No, it is because throwing exceptions in such cases will be
terribly costly. In case under consideration it is easy enough, though.

 Leo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 6 May 2002 11:14:48 GMT
Raw View
In article <VPHA8.7357$T_.164476@iad-read.news.verio.net>,
xleobx@qmailcomq.com wrote:
>>>See objection on tying "new" to a ctor.
>
>> What's the reference you have in your mind here?
>
>I did not fully understand the question, but do you want to pollute
>the code space with all possible combinations of operator new(...) and
>the ctor? operator new needs to be virtualized separately from the ctor.

I figure that the allocator is chosen statically by the compiler, and
could thus be embedded with the virtual table fuction call. For dynamic
allocator selections (i.e., a constructor can change it at rumtime), I do
not know -- I do not think that the C++ supports that now.

Othewise, I do not see the details of an implementation.

>> I just outlined the general idea -- the main (user) point is that after
>> the indicated allocator (operator new) is invoked, the dynamically chosen
>
>What if we have different operator new's for different derived classes?
>The allocator needs to be virtual as well, so a long-standing axiom
>that a method cannot be both static and virtual will be abolished.

So then I think it will merely be embedded with the virtual function call,
but statically chosen for each constructor by the compiler.

>> One would expect an exception so that the runtime system can properly
>> handle it. For example, not all objects are clonable, but there is no way
>> to prevent a runtime request for cloning an unclonable object. Then, if
>> the runtime system should not break, there should be a way to handle that,
>> not merely "undefined behavior". "Undefined behavior" is suitable in
>> situations where runtime breaks can be avoided by a static analysis, not
>> otherwise.
>
>Are you saying that runtime breaks due to object lifetime (see 3.8,
>it specifies undefined behavior left and right) can be avoided by static
>analysis?

No, the opposite: when moving into the dynamic picture, it is hard to tell
exactly what these runtime objects may experience by means of a static
analysis.

> No, it is because throwing exceptions in such cases will be
>terribly costly. In case under consideration it is easy enough, though.

Once one moves into the dynamic picture, there will be a lot of overhead
merely by the memory allocations: A typical "operator new" takes several
tens of cycles; some say it may even take hundreds of cycles. Just to get
the memory allocation, and nothing else.

Therefore, I think that the focus should be on making this runtime
environment safe, not worrying overly about overheads. Thus, use
exceptions that can ensure that the runtime behavior is safe.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 30 Apr 2002 21:51:38 GMT
Raw View
The discussions in the thread "Subject: Re: C++0x: Will there be a
this_t?", and the suggestions by <xleobx@qmailcomq.com> there, lead me to
the following suggestion of virtual constructors (constructors with
polymorphic behavior) to be added to the C++ standard:

With respect to a polymorphic class X, one may add the word "virtual" to a
declared constructor X(A), where A is a valid type argument (i.e., a list
of valid types). The implementation behavior is to add the corresponding
function
    new X(A)
to the virtual lookup table in a way that it can be accessed via the
type_info object.

This function can then be accessed polymorphicly via the typeid function:
If p is a polymorphic pointer, then typeid(*p)(a), where $a$ is of type A
(stacially checked by the C++ compiler), will yield that result. If
addition, if the class indicated by typeid(*p) does not have the
constructor defined, an exception should be thrown when typeid(*p)(a) is
being called.

As for the automatically generated constructors, including the copy
constructors X(const X&) and X(X&), I tend to think that when these are
defined also the corresponding new X(...) function should be added to the
virtual lookup table (in order to avoid the same embarrassment that
happened with the destructors). This would in particular mean that the
clone operators are added to the C++ polymorphic classes, because they can
be extracted as
    new typeid(*this)(*this)
I.e., one calls one of
    new X(const X&)
    new X(X&)
which traditionally otherwise might be written
    virtual X* X::clone() const;
    virtual X* X::clone();

I do not see all the ideas of an implementation of the above; but that
would be the general outline.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]