lifetime of static objects

Discussion in 'C++' started by Simon Elliott, Oct 11, 2004.

  1. 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?

    --
    Simon Elliott http://www.ctsn.co.uk
     
    Simon Elliott, Oct 11, 2004
    #1
    1. Advertising

  2. Simon Elliott wrote:

    > 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
     
    Victor Bazarov, Oct 11, 2004
    #2
    1. Advertising

  3. On 11/10/2004, Victor Bazarov wrote:

    > 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.


    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.)


    --
    Simon Elliott http://www.ctsn.co.uk
     
    Simon Elliott, Oct 11, 2004
    #3

  4. >
    > 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
     
    John Harrison, Oct 11, 2004
    #4
  5. * "Simon Elliott" <Simon at ctsn.co.uk>:
    > 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".

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Oct 11, 2004
    #5
  6. Simon Elliott

    DaKoadMunky Guest

    >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.
     
    DaKoadMunky, Oct 12, 2004
    #6
  7. "DaKoadMunky" <> wrote in message
    news:...
    > >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.
    >


    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
     
    John Harrison, Oct 12, 2004
    #7
  8. On 12/10/2004, John Harrison wrote:
    > > 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.


    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.

    --
    Simon Elliott http://www.ctsn.co.uk
     
    Simon Elliott, Oct 12, 2004
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. gorda
    Replies:
    5
    Views:
    5,077
    akhyls
    Mar 7, 2010
  2. Simon Elliott

    Lifetime of static objects revisited

    Simon Elliott, Dec 2, 2004, in forum: C++
    Replies:
    5
    Views:
    423
    Simon Elliott
    Dec 4, 2004
  3. Vagif Abilov
    Replies:
    3
    Views:
    18,296
    Laurent Bugnion
    May 24, 2006
  4. Stefan Ram
    Replies:
    14
    Views:
    561
    James Kanze
    Apr 13, 2009
  5. Elie Grouchko

    lifetime of ASP objects

    Elie Grouchko, May 22, 2005, in forum: ASP General
    Replies:
    0
    Views:
    117
    Elie Grouchko
    May 22, 2005
Loading...

Share This Page