Class member function calls inside ctor and dtor

Steven Schveighoffer schveiguy at yahoo.com
Sun Jan 28 00:42:26 UTC 2018


On 1/27/18 12:01 PM, Jonathan M Davis wrote:
> On Saturday, January 27, 2018 16:18:26 Thomas Mader via Digitalmars-d wrote:
>> On Saturday, 27 January 2018 at 14:48:08 UTC, Johan Engelen wrote:
>>> I'm working on devirtualization and for that it's crucial to
>>> know some spec details (or define them in the spec if they
>>> aren't yet).
>>>
>>> Currently, calling non-final member functions in the destructor
>>> is allowed and these indirect calls are to the possibly
>>> overridden functions of derived classes. That is, inside a base
>>> class constructor, the object's type is its final type (so
>>> possibly of a derived class). This is the same in the
>>> destructor. Thus, the object's dynamic type does not change
>>> during its lifetime.
>>
>> Can't answer your question but have a little question.
>> How is the behavior different to the situation in C++? They argue
>> that it's not good to call virtual methods in Con-/Destructors in
>> https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-ctor-virtu
>> al
>>
>> So I guess it should better be not used in D as well?
> 
> D solved that problem. In C++, when you're in the base class constructor,
> the object doesn't have its derived type yet. It's still just the base
> class. Each class level gets add as it's constructed (the same in reverse
> with the destructor). You don't have a full object until all constructors
> have been run, and once you start running destructors, you don't have a full
> class anymore either.
> 
> In D, on the other hand, the object is initialized with its init value
> _before_ any constructors are run. So, it's a full object with a full type,
> and everything virtual is going to get the type right.

Well, a virtual function may expect that the ctor has been run, and 
expect that members are different from their init values.

However, because you can initialize that data before calling the 
superclass' constructor, you can alleviate this problem as well.

For instance, the invariant may be called when you call the virtual 
function:

import std.stdio;

class A
{
     this() { writeln("A.ctor"); foo(); }
     void foo() { writeln("A.foo"); }
}

class B : A
{
     int x;
     this() {
         writeln("B.ctor");
         x = 1; // note the intialization before calling the base class
         super();
     }
     invariant {
         writeln("invariant!");
         assert(x == 1);
     }
     override void foo() { writeln("B.foo"); }
}

void main()
{
     auto b = new B;
}

output:
B.ctor
A.ctor
invariant! <- before calling foo
B.foo
invariant! <- after calling foo
invariant! <- after constructors are done

-Steve


More information about the Digitalmars-d mailing list