Q: Order of construction for objects

J

Jakob Bieling

Hi,

I am aware of the fact, that the order of construction of global
objects is unspecified. But I am in a situation, where I need to
guarantee, that one object is created before others (not all others,
just all objects of a specified type). I came up with the following
solution, but I am not sure, if it does solve my problem:

class first
{
};

class A
{
static first first_obj;
};

int main ()
{
A mya;
}

class A (further implementation omitted) will rely on some
initialization done by class first. Is it guaranteed that this
initialization will be all done, before I use A?

thanks!
 
R

Rolf Magnus

Jakob said:
Hi,

I am aware of the fact, that the order of construction of global
objects is unspecified.

Not entirely. Within one translation unit, it is well-defined.
But I am in a situation, where I need to guarantee, that one object is
created before others (not all others, just all objects of a specified
type).

The typical way to do this is by using the singleton pattern. Something like
this:

class first
{
static first& instance()
{
static first inst;
return inst;
}

private:
first() {}

// prevent copying
first(first&);
void operator=(first&);
};

Then you only use the object through the instance() member function. This
guarantees that the object gets created in the moment it is needed the
first time.
 
J

Jakob Bieling

Rolf Magnus said:
Not entirely. Within one translation unit, it is well-defined.


The typical way to do this is by using the singleton pattern.
Something like
this:

class first
{
static first& instance()
{
static first inst;
return inst;
}

private:
first() {}

// prevent copying
first(first&);
void operator=(first&);
};

Then you only use the object through the instance() member function.
This
guarantees that the object gets created in the moment it is needed the
first time.


To be more exact, I will not need the object itself .. it only
contains a ctor and a dtor, which take care of initialization and
cleanup. And that initialization is needed for class A.

I could do the initialization at startup before anything else, but I
would like to automate this.

Thanks for the help!
 
J

John Carson

Jakob Bieling said:
Hi,

I am aware of the fact, that the order of construction of global
objects is unspecified.

It is unspecified if they are in different translation units. If they are in
the same translation unit, then construction is in the same order as
definition. Section 3.6.2/1 of the standard:

"Objects with static storage duration (3.7.1) shall be zero-initialized
(8.5) before any other initialization takes place. Zero-initialization and
initialization with a constant expression are collectively called static
initialization; all other initialization is dynamic initialization. Objects
of POD types (3.9) with static storage duration initialized with constant
expressions (5.19) shall be initialized before any dynamic initialization
takes place. Objects with static storage duration defined in namespace scope
in the same translation unit and dynamically initialized shall be
initialized in the order in which their definition appears in the
translation unit."
But I am in a situation, where I need to
guarantee, that one object is created before others (not all others,
just all objects of a specified type). I came up with the following
solution, but I am not sure, if it does solve my problem:

class first
{
};

class A
{
static first first_obj;
};


This only declares first_obj, where do you define it?
int main ()
{
A mya;
}

class A (further implementation omitted) will rely on some
initialization done by class first. Is it guaranteed that this
initialization will be all done, before I use A?


Section 3.6.2/3 of the standard:

"It is implementation-defined whether or not the dynamic initialization
(8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the
first statement of main. If the initialization is deferred to some point in
time after the first statement of main, it shall occur before the first use
of any function or object defined in the same translation unit as the object
to be initialized.31) [Example:
// – File 1 –
#include "a.h"
#include "b.h"
B b;
A::A(){
b.Use();
}

// – File 2 –
#include "a.h"
A a;

// – File 3 –
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main() {
a.Use();
b.Use();
}
It is implementation-defined whether either a or b is initialized before
main is entered or whether the initializations are delayed until a is first
used in main. In particular, if a is initialized before main is entered, it
is not guaranteed that b will be initialized before it is used by the
initialization of a, that is, before A::A is called. If, however, a is
initialized at some point after the first statement of main, b will be
initialized prior to its use in A::A. ]"

Section 9.4.2/7:

"Static data members are initialized and destroyed exactly like non-local
objects (3.6.2, 3.6.3)."

From all this, we may conclude: the initialization of

static first first_obj;

"shall occur before the first use [in main()] of any function or object
defined in the same translation unit as the object to be initialized [i.e.,
first_obj]." So if first_obj and A are defined in the same translation unit,
first_obj must be initialised before the first use of A in main(). At least
that is how it appears to me.
 
I

Ioannis Vranos

Jakob said:
Hi,

I am aware of the fact, that the order of construction of global
objects is unspecified. But I am in a situation, where I need to
guarantee, that one object is created before others (not all others,
just all objects of a specified type). I came up with the following
solution, but I am not sure, if it does solve my problem:

class first
{
};

class A
{
static first first_obj;
};

int main ()
{
A mya;
}

class A (further implementation omitted) will rely on some
initialization done by class first. Is it guaranteed that this
initialization will be all done, before I use A?


Yes. However all global objects would be initialised before the invocation of main().

In any case, first_obj will be initialised before any use of class A.
 
I

Ioannis Vranos

Ioannis said:
Yes. However all global objects would be initialised before the
invocation of main().

In any case, first_obj will be initialised before any use of class A.


.... even if class A is defined in some local scope (like a function, method or even a
block). That is, in any scope.
 
J

Jakob Bieling

John Carson said:

--- A.h ---
This only declares first_obj, where do you define it?

Oops. It should have been in a different translation unit:

--- A.cpp ---

first A::first_obj;

--- main.cpp ---
Section 3.6.2/3 of the standard:

"It is implementation-defined whether or not the dynamic
initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace
scope is done before the first statement of main. If the
initialization is deferred to some point in time after the first
statement of main, it shall occur before the first use of any function
or object defined in the same translation unit as the object to be
initialized.31) [Example:

Since first_obj is in its own translation unit, it may possibly not
be initialized at all?
From all this, we may conclude: the initialization of

static first first_obj;

"shall occur before the first use [in main()] of any function or
object defined in the same translation unit as the object to be
initialized [i.e., first_obj]." So if first_obj and A are defined in
the same translation unit, first_obj must be initialised before the
first use of A in main(). At least that is how it appears to me.

It would be a different translation unit. first_obj is in a
translation unit by itself, with no code of A in it. I should add, that
A actually is a template, and thus the definition of its member
functions are inlined. Just let me create a new example, which more
reflects the actual problem:

--- class.h ---

class API_init
{
API_init() { init_some_API (); }
~API_init() { cleanup_some_API (); }
};

template <typename T>
class A
{
static API_init init_obj;

A ()
{
API_function_that_relies_on_init ();
}

void func ()
{
other_API_function_that_relies_on_init ();
}
};


--- class.cpp ---

#include "class.h"

API_init A::init_obj;


--- main.cpp ---

#include "class.h"

A a1;

int main ()
{
A a2;
a1.func ();
a2.func ();
}


Will the ctor of API_init be called *before* the ctor of A is
called? If not, or if that is not guaranteed, then it may be possible
that the API I will use is not initialized properly, making subsequent
calls to other API functions fail. And that is basically the problem I
am trying to solve.

Thanks
 
J

Jakob Bieling

Ioannis Vranos said:
... even if class A is defined in some local scope (like a function,
method or even a block). That is, in any scope.


Even if class A does not call any member function of first_obj? I
posted a more exact example in reply to John's answer .. so if your 'in
any case' applies to that case as well, my problem would be solved :)

Thanks!
 
R

Rolf Magnus

Jakob said:
To be more exact, I will not need the object itself .. it only
contains a ctor and a dtor, which take care of initialization and
cleanup. And that initialization is needed for class A.

I could do the initialization at startup before anything else, but I
would like to automate this.

Well, you can also do that with the singleton. You can put your
initialization into the constructor and the cleanup in the destructor.
 
J

Jakob Bieling

Rolf Magnus said:
Well, you can also do that with the singleton. You can put your
initialization into the constructor and the cleanup in the destructor.


Uh yes, but 'instance' will never be called, because an instance is
not needed. The class 'first' does not contain any functionality, other
than initializing an API (and cleaning up). I wanted to avoid having a
dummy call in all class A ctors (either to a global function containing
the static object, or the member function as in your example), so I came
up with the static-member-of-class idea.
Since John's post I realized that the cut-down example I gave you,
did not really reflect the problem, so I wrote a new one in reply to
John's answer.
Basically, I want the initialization code to be automatically
executed (ie. no explicit function calls) before I use the API. Same for
the cleanup code: cleanup after I am done with everything. But I assumed
once the first problem is solved, the second will automatically be
solved, because destructions takes place in the reverse order of
construction. Or am I assuming too much?

Thanks!
 
J

John Carson

[snip]
Just let me create a new example, which more
reflects the actual problem:

--- class.h ---

class API_init
{
API_init() { init_some_API (); }
~API_init() { cleanup_some_API (); }
};

template <typename T>
class A
{
static API_init init_obj;

A ()
{
API_function_that_relies_on_init ();
}

void func ()
{
other_API_function_that_relies_on_init ();
}
};


--- class.cpp ---

#include "class.h"

API_init A::init_obj;


--- main.cpp ---

#include "class.h"

A a1;

int main ()
{
A a2;
a1.func ();
a2.func ();
}


Will the ctor of API_init be called *before* the ctor of A is
called? If not, or if that is not guaranteed, then it may be possible
that the API I will use is not initialized properly, making subsequent
calls to other API functions fail. And that is basically the problem I
am trying to solve.


As far as I can see, the Standard does not guarantee that the constructor of
API_init will be called first. As a practical matter, many implementations
probably do initialise all global variables before main(), but this is not
guaranteed.

I think that the simplest way to solve your problem is to ditch the static
class member and have a local static variable in the constructor of class A.
Make it:

template <typename T>
class A
{
A ()
{
static API_init init_obj;
API_function_that_relies_on_init ();
}

void func ()
{
other_API_function_that_relies_on_init ();
}
};
 
I

Ioannis Vranos

Jakob said:
Even if class A does not call any member function of first_obj? I
posted a more exact example in reply to John's answer .. so if your 'in
any case' applies to that case as well, my problem would be solved :)


Yes in any case. static objects of a class, global and namespace objects are initialised
before main(), in an order that is up to the implementation.
 
V

Victor Bazarov

Ioannis said:
Yes in any case. static objects of a class, global and namespace
objects are initialised before main(), in an order that is up to the
implementation.

Not always. Within the same translation unit they are initialised in
the order of definition, according to the Standard. The order of
initialisation of static objects in different translation units is
unspecified.

V
 
A

Alf P. Steinbach

* Ioannis Vranos:
Yes in any case. static objects of a class, global and namespace objects
are initialised before main(),

Sorry.

§3.6.2/3
"If the [dynamic] initialization [of an object] is deferred to some point in
time after the first statement of 'main', it shall occur before the first
use of any function or object defined in the same translation unit as the
object to be initialized."

This is the full extent of dynamic library support in the standard (assuming
that's what it is, which is natural to believe). Effectively it means that
if you want a more or less deterministic initialization order you should
call some module initialization function from 'main'. That's consistent
with C++ not taking any other module-related responsibilities, either.

in an order that is up to the implementation.

Sorry again; see Victor's reply.
 
M

ma740988

This is an interesting post. I'm currently struggling with source code
- I inherited from someone else - where I have a need to - do
global/static initilization on an 'm_rec' object. The current
approach has the m_rec object instantiated dynamically within the
rec_win_impl constructor. So now a stripped down version of the
source code:

//
//--------------------------------------------------------------
// rec_impl.h
#ifndef REC_IMPL_H
#define REC_IMPL_H

class rec_win {};
class rec; // forward declaration of rec.

class rec_impl : public rec_win
{
public:
rec_impl();
~rec_impl();

private:
rec *m_rec; // will need to change this
};

#endif

//
//--------------------------------------------------------------
// rec_impl.cpp
#include "rec.h"
rec_impl::rec_impl()
: rec_win()
{
m_rec = new rec(); //will need to change this
}

//
//--------------------------------------------------------------
// rec.h
#ifndef REC_H
#define REC_H

#include "rec_ic_data.h"

class rec {
rec_ic_data m_rec_data;
public:
rec();
void update();
};
#endif

//
//--------------------------------------------------------------
// rec.cpp
#include "rec.h"

rec::rec()
{
}
void rec::update(rec_ic_data& upd)
{
m_rec_data = upd;
}

void rec::get_data()
{
//persistent *p = persistent::createInstance(stream);
//p->execute(); // calls rec_ic_data.execute();
}

//
//--------------------------------------------------------------
// rec_ic_data.h
#ifndef REC_IC_DATA_H
#define REC_IC_DATA_H

struct rec_ic_data {
rec_ic_data() {}
void execute() {
m_rec.update(*this); // call the update function in rec.
}
};
#endif


//
//--------------------------------------------------------------
// main.cpp
# include "rec_impl.h"

int main()
{
rec_impl *m_rec_impl = new rec_impl();
delete m_rec_impl;
}
----------------------------------------------------------------

The execute member function in get_data makes a call 'virtually' to
execute member function in rec_ic_data.
Once this is done, all I need to do is call the update member function
in rec. To do this: I need a global intance of m_rec. I'm confused
though on how to achieve this, since m_rec_impl ( I suspect now I'll
need to initialize m_rec_impl globally) needs to be intiailized first.

I was advised that a 'manager' class is usually the ideal approach when
dealing with global initilization such as this. I tend to run amok
with this 'static/global' initilization stuff. That said, thanks for
your assistance.
 
I

Ioannis Vranos

Victor said:
Not always. Within the same translation unit they are initialised in
the order of definition, according to the Standard. The order of
initialisation of static objects in different translation units is
unspecified.


Yes. Actually this is what I had in mind, but never mind, I should have been more accurate
in description. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top