lifetime of static objects

S

Simon Elliott

Consider the following, incorrect, code:


#pragma hdrstop
#include <condefs.h>
#include <iostream>
#include <conio.h>

class bar
{
private:
operator = (const bar&);
bar(const bar&);
public:
bar(void)
{
cout << "bar: constructor " << std::endl;
}
~bar()
{
cout << "bar: destructor" << std::endl;
}
void Hello(int thing)
{
cout << "bar: say hello " << thing << std::endl;
}
void Goodbye(int thing)
{
cout << "bar: wave goodbye " << thing << std::endl;
}
};


class foo
{
private:
int thing_;
foo();
operator = (const foo&);
foo(const foo&);
static bar &instance()
{
static bar theInstance;
return theInstance;
}
public:
explicit foo(int thing):thing_(thing)
{
cout << "foo: constructor " << thing_ << std::endl;
bar& the_bar = instance();
the_bar.Hello(thing_);
}
~foo()
{
bar& the_bar = instance();
the_bar.Goodbye(thing_);
cout << "foo: destructor " << thing_ << std::endl;
}
};

static foo foo1(1);
static foo foo2(2);

int main(int argc, char **argv)
{
return 0;
}

The output from this is:

foo: constructor 1
bar: constructor
bar: say hello 1
foo: constructor 2
bar: say hello 2
bar: destructor
bar: wave goodbye 2
foo: destructor 2
bar: wave goodbye 1
foo: destructor 1

Which isn't what's required: methods in the static instance of bar are
being called after bar's destructor has been called.

How would I change the code to make sure that the static instance of
bar is destroyed last?
 
V

Victor Bazarov

Simon said:
Consider the following, incorrect, code:


#pragma hdrstop
#include <condefs.h>
#include <iostream>
#include <conio.h>

class bar
{
private:
operator = (const bar&);
bar(const bar&);
public:
bar(void)
{
cout << "bar: constructor " << std::endl;
}
~bar()
{
cout << "bar: destructor" << std::endl;
}
void Hello(int thing)
{
cout << "bar: say hello " << thing << std::endl;
}
void Goodbye(int thing)
{
cout << "bar: wave goodbye " << thing << std::endl;
}
};


class foo
{
private:
int thing_;
foo();
operator = (const foo&);
foo(const foo&);
static bar &instance()
{
static bar theInstance;
return theInstance;
}
public:
explicit foo(int thing):thing_(thing)
{
cout << "foo: constructor " << thing_ << std::endl;
bar& the_bar = instance();
the_bar.Hello(thing_);
}
~foo()
{
bar& the_bar = instance();
the_bar.Goodbye(thing_);
cout << "foo: destructor " << thing_ << std::endl;
}
};

static foo foo1(1);
static foo foo2(2);

int main(int argc, char **argv)
{
return 0;
}

The output from this is:

foo: constructor 1
bar: constructor
bar: say hello 1
foo: constructor 2
bar: say hello 2
bar: destructor
bar: wave goodbye 2
foo: destructor 2
bar: wave goodbye 1
foo: destructor 1

Which isn't what's required: methods in the static instance of bar are
being called after bar's destructor has been called.

How would I change the code to make sure that the static instance of
bar is destroyed last?

You have to create it first. Pull the 'static bar theInstance' from
the function and place it in the file scope (without 'static') before
the other two objects. BTW, you didn't need "static" for them either,
unless you don't want them to be visible from other modules.

Victor
 
S

Simon Elliott

How would I change the code to make sure that the static instance of

You have to create it first. Pull the 'static bar theInstance' from
the function and place it in the file scope (without 'static') before
the other two objects.

That would make the objects harder to use. I want people to be able to
use a foo without thinking about a bar. (I'd like to be able to remove
all visibility of bar from my foo definition, but I suspect that's a
bridge too far.)
 
J

John Harrison

How would I change the code to make sure that the static instance of
bar is destroyed last?

Destruction is always in reverse order of construction. So the only way to
ensure that bar is destroyed last is to construct it first.

john
 
A

Alf P. Steinbach

* "Simon Elliott said:
Consider the following, incorrect, code:


#pragma hdrstop
#include <condefs.h>
#include <iostream>
#include <conio.h>

class bar
{
private:
operator = (const bar&);
bar(const bar&);
public:
bar(void)
{
cout << "bar: constructor " << std::endl;
}
~bar()
{
cout << "bar: destructor" << std::endl;
}
void Hello(int thing)
{
cout << "bar: say hello " << thing << std::endl;
}
void Goodbye(int thing)
{
cout << "bar: wave goodbye " << thing << std::endl;
}
};


class foo
{
private:
int thing_;
foo();
operator = (const foo&);
foo(const foo&);
static bar &instance()
{
static bar theInstance;
return theInstance;
}
public:
explicit foo(int thing):thing_(thing)
{
cout << "foo: constructor " << thing_ << std::endl;
bar& the_bar = instance();
the_bar.Hello(thing_);
}
~foo()
{
bar& the_bar = instance();
the_bar.Goodbye(thing_);
cout << "foo: destructor " << thing_ << std::endl;
}
};

static foo foo1(1);
static foo foo2(2);

int main(int argc, char **argv)
{
return 0;
}

The output from this is:

foo: constructor 1
bar: constructor
bar: say hello 1
foo: constructor 2
bar: say hello 2
bar: destructor
bar: wave goodbye 2
foo: destructor 2
bar: wave goodbye 1
foo: destructor 1

Which isn't what's required: methods in the static instance of bar are
being called after bar's destructor has been called.

How would I change the code to make sure that the static instance of
bar is destroyed last?

The only sure way (i.e. without imposing "invisible" restrictions on usage)
would be to make bar instance reference counted. I think. You can find
an example of that idea in Andrei Alexandrescu's "Modern C++ Design".
 
D

DaKoadMunky

Destruction is always in reverse order of construction. So the only way to
ensure that bar is destroyed last is to construct it first.

Isn't that order based not on the order in which constructors were called but
the order in which constructors were completed?

In the OP's case the constructor for Foo is called first but the constructor
for Bar completes before the Foo constructor therefore the Bar destructor
should be called last because it was the first fully constructed object.

Not having the standard I can't provide support for this, but I did see it
discussed elsewhere on the net and the example code posted was virtually
identical to the OP's.
 
J

John Harrison

DaKoadMunky said:
Isn't that order based not on the order in which constructors were called
but
the order in which constructors were completed?

In the OP's case the constructor for Foo is called first but the
constructor
for Bar completes before the Foo constructor therefore the Bar destructor
should be called last because it was the first fully constructed object.

Not having the standard I can't provide support for this, but I did see it
discussed elsewhere on the net and the example code posted was virtually
identical to the OP's.

You are right, 3.6.3 para 1 says that destructors are called in reverse
order of the completion of their constructor calls.

Looks like the OP's compiler is not implementing this correctly.

john
 
S

Simon Elliott

You are right, 3.6.3 para 1 says that destructors are called in
reverse order of the completion of their constructor calls.

Looks like the OP's compiler is not implementing this correctly.

That's entirely possible since it's BCB3 which is quite old.

But with BCB6 I get this:

foo: constructor 1
bar: constructor
bar: say hello 1
foo: constructor 2
bar: say hello 2
bar: destructor
bar: constructor
bar: wave goodbye 2
foo: destructor 2
bar: wave goodbye 1
foo: destructor 1

As you can see, bar is destroyed and then rebuilt. And then not
destroyed second time round. That doesn't seem right to me.

When I've got the chance I'll try this on gcc on my hosting provider's
unix box.
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top