Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Calling member during construction

90 views
Skip to first unread message

Vir Campestris

unread,
Nov 14, 2017, 4:09:52 PM11/14/17
to
(This is derived from real code, but that's horribly complicated. I
didn't write it)

Suppose there is a class omega that has three members
class omega {
alpha a;
beta b;
gamma c;

And the constructor is something like this:

omega::omega(): a(1), b(this), c(2) {...}

- Is there anything in the language spec that forbids this?
- Assuming b doesn't use c (at least until later), will the code behave
correctly?

In the real code beta handles inter-object communication, and may
receive signals from other threads.

Andy

Richard

unread,
Nov 14, 2017, 4:14:30 PM11/14/17
to
[Please do not mail me a copy of your followup]

Vir Campestris <vir.cam...@invalid.invalid> spake the secret code
<oufm2l$ev4$1...@dont-email.me> thusly:
Nothing in the language specifciation forbids this.

Assuming that beta's constructor doesn't do anything more with its
argument than store it, you're fine.

If beta's constructor needs to call methods on the passed in omega
pointer, then you've got a chicken-and-egg situation. The omega
instance hasn't been fully constructed so it is in a state that can't
guarantee anything about invariants assumed by its methods.

The typical solution to this is to refactor the code into two-phase
construction. Phase 1 gets all the objects constructed with the
pointer references between them. Phase 2 calls any necessary methods
to complete the construction.

We can't answer if you need 2 phase construction based on the code
you've shown because we don't know what beta's constructor does with
the passed in pointer to the omega.

--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Alf P. Steinbach

unread,
Nov 14, 2017, 6:19:01 PM11/14/17
to
I wouldn't recommend two phase construction in general.

Usually there are better ways.

The situation you describe is a FAQ: <url:
https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom>.


Cheers & hth.,

- Alf

Öö Tiib

unread,
Nov 14, 2017, 6:36:10 PM11/14/17
to
Virtuals can't solve the fundamental problem anyway.
In C++ type of object can't change after its creation. Therefore in C++
we can observe three different phases of construction:
1) figure (dynamically) out what is the most derived type that is needed
2) collect together all the required bits and pieces of information for
construction of type determined in 1)
3) construct type determined in 1) using data gathered in 2).
Every of the 3 steps may fail for piles of obvious reasons.

Richard

unread,
Nov 14, 2017, 8:08:05 PM11/14/17
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<ouftkd$5gr$1...@dont-email.me> thusly:
Such as?
In this case, it's worse than calling virtual functions from a c'tor
because the other class (beta) might attemp to call non-virtual
methods on omega before omega is ready to handle them. We're passing
our this pointer in the member initializer, so other initializers may
not yet have run and certainly the body of the c'tor for omega hasn't
run yet.

The FAQ is describing two-phase construction so that calls to virtual
methods in the c'tor will resolve properly.

Paavo Helde

unread,
Nov 15, 2017, 1:57:46 AM11/15/17
to
If b does not use omega until later, then it is OK. However, from your
mention of threads I suspect that beta might leak a pointer to omega or
itself to other threads too early, causing all kind of havoc. The rest
of my reply assumes this kind of nasty scenarios.

Construction and destruction of multithread-shared objects is always
problematic. Construction is a bit simpler in that one can ensure
relatively easily that an half-constructed object does not become
visible to other threads. This means that the object is exposed to other
threads only after the most derived class constructor has completed
("two-phase construction"), or at least only near the end of the
constructor of the most derived class. The 'sealed' keyword may help to
ensure the class remains the most derived class.

If the beta member exposes a pointer/reference of omega to other threads
in its constructor, then this is a big no-no. The other threads must not
know about omega before its constructor has been completed. Otherwise
they may try to access it before completion, or worse yet, after the
omega object has been destroyed by any reason, either during
construction or shortly afterwards. The latter just reflects the fact
that destruction of a thread-shared object is even more problematic than
construction ("an object cannot protect aginst its own destruction").

A pretty robust solution is to allocate all thread-shared objects with
std::make_shared() and only pass a std::shared_ptr or std::weak_ptr to
other threads. This forces one to use 2-phase construction, which is
arguably a good thing in this scenario (anything that avoids UB is a
good thing!). As long as a thread has a non-null std::shared_ptr or is
able to construct one from a std::weak_ptr, it is guaranteed that the
full object is alive and can be used properly.

An example demoing a factory function doing the two-phase construction:

static std::shared_ptr<omaga> omega::CreateOmega(...) {

std::shared_ptr<omega> p = std::make_shared<omega>(...);
p->b.NotifyOtherThreads(p);
return p;

}

Indeed, if you need to fix some "horribly complicated" real code messing
with multithreaded access, then I suggest to refactor it to use
std::shared_ptr in order to enforce proper access. By using raw pointers
or references one must know extremely well what one is doing, which may
not be humanly possible in a messed-up codebase.

hth
Paavo








Vir Campestris

unread,
Nov 15, 2017, 3:50:32 AM11/15/17
to
Thanks everyone. I'll continue my discussion with the code's author. I
have a feeling this will be - interesting. I know there's at least one
race condition.

Andy

Alf P. Steinbach

unread,
Nov 15, 2017, 7:59:36 AM11/15/17
to
No. I was mainly responsible for adding that item to the FAQ. It's not
about two phase construction.

Richard

unread,
Nov 15, 2017, 12:11:47 PM11/15/17
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<ouhdn1$cfm$1...@dont-email.me> thusly:

>On 11/15/2017 2:07 AM, Richard wrote:
>
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
>> <ouftkd$5gr$1...@dont-email.me> thusly:
>>
>>> I wouldn't recommend two phase construction in general.
>>>
>>> Usually there are better ways.
>>
>> Such as?

This is actually the question I would like answered.

The very next answer in the FAQ describes two-phase initialization. I
didn't realize they were separate Q&As at first. I don't think I've
ever looked at this FAQ in this form before. I'm used to the usenet
FAQ that became the book by Marshall Cline.

Alf P. Steinbach

unread,
Nov 15, 2017, 1:10:15 PM11/15/17
to
On 11/15/2017 6:11 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
> <ouhdn1$cfm$1...@dont-email.me> thusly:
>
>> On 11/15/2017 2:07 AM, Richard wrote:
>>
>>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
>>> <ouftkd$5gr$1...@dont-email.me> thusly:
>>>
>>>> I wouldn't recommend two phase construction in general.
>>>>
>>>> Usually there are better ways.
>>>
>>> Such as?
>
> This is actually the question I would like answered.

Then you could read the FAQ that I linked to to answer precisely that
question.

For convenience, here's that URL again: <url:
https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom>.


> The very next answer in the FAQ describes two-phase initialization.

No, the next answer in the FAQ is about “I’m getting the same thing with
destructors: calling a virtual on my this object from my base class’s
destructor ends up ignoring the override in the derived class; what’s
going on?”


> I didn't realize they were separate Q&As at first. I don't think
> I've ever looked at this FAQ in this form before. I'm used to the
> usenet FAQ that became the book by Marshall Cline.
The items in this section are from Marshall's FAQ. It's Marshall's
wording, not mine.

Most of ISO C++ FAQ is Marshall's FAQ verbatim.

The difference is mostly that Bjarne Stroustrup's FAQ has been
incorporated and that some stuff has been added by the new co-editors,
which are Andrei Alexandrescu, Bjarne Stroustrup and Herb Sutter.

Richard

unread,
Nov 15, 2017, 6:30:01 PM11/15/17
to
[Please do not mail me a copy of your followup]

OK, I finally found it buried at the end of the answer. I kept
getting distracted by it saying "you can do two-phase initialization"
and much further down on the answer was the split hierarchy approach.
I was aware of this alternative. However, I haven't used it much
because when I encounter this problem, the split hierarchy would
require significantly more refactoring than using a factory method.

While I agree that this approach is an alternative to two-phase
construction, whether or not it is better can only be evaluated in the
larger context of actual code. (No surprise really, this happens in
class design all the time. Different forces influence the design and
not all contexts have the forces present to the same degree.)

Rick C Hodgin

unread,
Nov 17, 2017, 10:19:27 AM11/17/17
to
A request for each of you

Original post : https://groups.google.com/forum/#!topic/alt.os.development/nvGbmY74C-4


To my fellow "Usenet group"ies:

I come before you today with a request for each of you. I ask
you to give it an ear and ponder it in your heart. Consider it
for a time each day and think about what it means to the baseline
fundamental views we hold in our lives.

-----
My request is that you consider what this means to your self-
image: You were created. You do have a purpose. You were not
an accident of random chance in this universe. You were, instead,
specifically and purposefully hand-crafted by God, hand-placed
into this world where you are, with a purpose to have a real im-
pact upon this world. To further realize that within the creation
of your existence, the one creating you had a real purpose in do
doing. God created you with a goal of certain things He wants you
to do in this world, for example.

Think about this idea: That you were created, that you do have a
real purpose, and that you will go on after you leave this world,
and that you do have a choice today regarding how you will live
your life, and that the warning given you by your very creator is
that there is a real enemy here in this world, responsible for all
that we see wrong here, who seeks to mislead you, trick you, trap
you, and ultimately destroy your soul by leading you away from God,
but if you will give God an ear, and stop hardening your heart
toward Him, that He will guide you not only to safety in this world,
but to the fullest, richest prosperity in Him.

Think about this. Read it a few times. Make sure you get a clear
understanding: You were created specifically by God. You have a
real purpose, and there are two paths before you: one leading to
forgiveness for the wrong you've done, to be a part of God's plan
for your life, one that keeps you unforgiven in the wrong you've
done and is leading away from God and God's plan for your life.

-----
God created you for greatness. He loves you. He will lead and
guide and protect and save you from all evil. But He also honors
you too much to violate His greatest gift to you: your volition.
He will not violate your free will to choose. But look into Him
and see how He's revealed Himself through His Son. The Bible
gives us a view of God that explains things in a way which really
resonates on the inside if you're willing to receive it. But if
you harden your heart, it will always only be a book of laughable
tales and fantasies.

The choice is yours, but the truth speaks to you. You were God's
creation. You were made special. You do have a purpose. And
you will go on after you leave this world. God has a plan for you
and will save you from everything bad, and give you a real and
secure future that dwells in fullest, richest prosperity for you,
His beloved and held dear, most special creation.

Thank you,
Rick C. Hodgin
0 new messages