lifetime of static objects

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Simon Elliott

    #1

    lifetime of static objects

    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_(t hing)
    {
    cout << "foo: constructor " << thing_ << std::endl;
    bar& the_bar = instance();
    the_bar.Hello(t hing_);
    }
    ~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
  • Victor Bazarov

    #2
    Re: lifetime of static objects

    Simon Elliott wrote:
    [color=blue]
    > 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_(t hing)
    > {
    > cout << "foo: constructor " << thing_ << std::endl;
    > bar& the_bar = instance();
    > the_bar.Hello(t hing_);
    > }
    > ~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?[/color]

    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

    Comment

    • Simon Elliott

      #3
      Re: lifetime of static objects

      On 11/10/2004, Victor Bazarov wrote:
      [color=blue]
      > How would I change the code to make sure that the static instance of[color=green]
      > > bar is destroyed last?[/color]
      >
      > 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.[/color]

      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

      Comment

      • John Harrison

        #4
        Re: lifetime of static objects

        [color=blue]
        >
        > How would I change the code to make sure that the static instance of
        > bar is destroyed last?
        >[/color]

        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


        Comment

        • Alf P. Steinbach

          #5
          Re: lifetime of static objects

          * "Simon Elliott" <Simon at ctsn.co.uk>:[color=blue]
          > 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_(t hing)
          > {
          > cout << "foo: constructor " << thing_ << std::endl;
          > bar& the_bar = instance();
          > the_bar.Hello(t hing_);
          > }
          > ~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?[/color]

          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?

          Comment

          • DaKoadMunky

            #6
            Re: lifetime of static objects

            >Destruction is always in reverse order of construction. So the only way to[color=blue]
            >ensure that bar is destroyed last is to construct it first.[/color]

            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.








            Comment

            • John Harrison

              #7
              Re: lifetime of static objects


              "DaKoadMunk y" <dakoadmunky@ao l.com> wrote in message
              news:2004101119 3133.15036.0000 4765@mb-m02.aol.com...[color=blue][color=green]
              > >Destruction is always in reverse order of construction. So the only way
              > >to
              >>ensure that bar is destroyed last is to construct it first.[/color]
              >
              > 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.
              >[/color]

              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


              Comment

              • Simon Elliott

                #8
                Re: lifetime of static objects

                On 12/10/2004, John Harrison wrote:[color=blue][color=green]
                > > 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.
                > >[/color]
                >
                > 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.[/color]

                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

                Comment

                Working...