Topic: Guru of the Week #22: Object Lifetimes - Part I


Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/13
Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:

|>  Does it means that references *are* rebindable ? It would be
|>  the contrary of what everyone tell everyday.
|>
|>  int i, j, &r = i;
|>  new (&r) int& (j);
|>
|>  I think a clarification in the DWP (as a note) can't hurt.

Nothing to clarify here -- the above code is illegal, and will fail on
many machines.  Note that the expression &r returns the address of the
referred to value (in this case, i), and not the address of the
reference.

A reference cannot be reseated during its lifetime.  However, if the
reference is part of a larger object (a struct), then its lifetime is
that of the larger object -- explicitly calling the destructor on the
object, and then reconstructing it, causes the original reference to
cease to exist, and creates a new one.  In fact, I think that just
reconstructing an object with a reference, without destructing it first,
is guaranteed to work.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
        I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/14
Raw View
kanze@gabi-soft.fr (J. Kanze) wrote:
> A reference cannot be reseated during its lifetime.  However, if the
> reference is part of a larger object (a struct), then its lifetime is
> that of the larger object -- explicitly calling the destructor on the
> object, and then reconstructing it, causes the original reference to
> cease to exist, and creates a new one.  In fact, I think that just
> reconstructing an object with a reference, without destructing it first,
> is guaranteed to work.

Surprisingly, yes, you can rebind a reference variable during its lifetime.
To put James's words into code:

    class Foo
    {
    public:
                Foo();
                Foo(int &x) ref(x) { }
    private:
        int &   ref;        // A reference
    };

    void foobar()
    {
        int     x = 1;
        int     y = 2;

        Foo     obj(x);             // obj.ref is bound to x

        obj.~Foo();                 // obj is destructed in place
        new((void *)&obj) Foo(y);   // obj.ref is rebound to y
    }

Note that the destructor call is not mandatory (but it's probably a really
good idea).

Can a class containing a reference variable (such as 'Foo' above) rebind
the reference itself?  This is probably legal:

    void Foo::rebind(int &x)
    {
        this->~Foo();               // Criminy!
        new((void *)this) Foo(x);   // this->ref is rebound to x
    }

Is this a good idea?  That's a different question.  Probably not.

-- David R. Tribble, david.tribble@beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/15
Raw View
J. Kanze <kanze@gabi-soft.fr> writes:

> Valentin Bonnard <bonnardv@pratique.fr> writes:
>
> |>  Does it means that references *are* rebindable ? It would be
> |>  the contrary of what everyone tell everyday.
> |>
> |>  int i, j, &r = i;
> |>  new (&r) int& (j);
> |>
> |>  I think a clarification in the DWP (as a note) can't hurt.
>
> Nothing to clarify here -- the above code is illegal, and will fail on
> many machines. Note that the expression &r returns the address of the
> referred to value (in this case, i), and not the address of the
> reference.

Sorry, sorry, sorry (that's correct, how did I missed that ?)

It is very clear in the above code, but not in the following case:

> A reference cannot be reseated during its lifetime.  However, if the
> reference is part of a larger object (a struct), then its lifetime is
> that of the larger object -- explicitly calling the destructor on the
> object, and then reconstructing it, causes the original reference to
> cease to exist, and creates a new one.

_This_ should be made clear in the WP. It means that references
aren't const (and that T& const could means non-resetable reference
to T).

I call that a reseatable reference.
It should be explicitly written in the std.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/15
Raw View
David R Tribble wrote:
> Expanding on the theme of rebinding (or 'reseating') reference variables,
> I've cooked up a little more complicated example:
>
>     class Foo
>     {
>     public:
>                         Foo(int &i, double &d);
>
>         void            reseatI(int &x);        // See below
>         void            reseatD(double &x);     // See below
>
>     private:
>         int &           iRef;   // A reference member
>         double &        dRef;   // Another reference member
>
>                         Foo(int &o): iRef(o) { }
>                         Foo(double &o): dRef(o) { }

Sorry this is ill-formed: you must have all the members which
require innitilisation in your list (all const and references
members).

Perhaps you mean:

Foo(int &o): iRef(o), dRef(dRef) { }

> Is this a good idea?  On the one hand, it allows you to treat references
> like mutable pointers.  On the other hand, it breaks the implicit
> guarantee that a reference does not (or should not) change its binding
> once it has been instantiated.

I think it's a good beginning for a IOC++CC entry (when it will exists).

(For info on IOCCC, go to: http://reality.sgi.com/csp/ioccc/index.html.)

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/15
Raw View
Expanding on the theme of rebinding (or 'reseating') reference variables,
I've cooked up a little more complicated example:

    class Foo
    {
    public:
                        Foo(int &i, double &d);

        void            reseatI(int &x);        // See below
        void            reseatD(double &x);     // See below

    private:
        int &           iRef;   // A reference member
        double &        dRef;   // Another reference member

                        Foo(int &o): iRef(o) { }
                        Foo(double &o): dRef(o) { }
    };

    Foo::Foo(int &i, double &d):
        iRef(i), dRef(d)        // Bind the reference members
    {
        ...whatever...
    }

    void Foo::reseatI(int &o)
    {
        // Do not destruct *this
        new((void *)this) Foo(o);       // Rebinds this->iRef to o
    }

    void Foo::reseatD(double &o)
    {
        // Do not destruct *this
        new((void *)this) Foo(o);       // Rebinds this->dRef to o
    }

The private constructors of class Foo exist solely to allow for rebinding
the reference members of the class.

Clients of class Foo can create a Foo object with an initial binding to
two variables (an int and a double) and then change the reference bindings
by calling reseatI() and reseatD():

    void myFunc()
    {
        int     i;
        double  x;

        Foo     obj(i, x);      // obj.iRef bound to i,
                                // obj.dRef bound to x

        int     j;
        obj.reseatI(j);         // obj.iRef now bound to j

        double  y;
        obj.reseatD(y);         // obj.dRef now bound to y
    }

There's also the consideration of what happens when the private
constructors are invoked if Foo is a derived class; constructors for
the base class(es) may be invoked also.  If the base class contains
reference member variables, they can also be re-bound using the same
technique.

Is this a good idea?  On the one hand, it allows you to treat references
like mutable pointers.  On the other hand, it breaks the implicit
guarantee that a reference does not (or should not) change its binding
once it has been instantiated.

--------------------.      BEA Systems, Inc. ,-.  +1-972-738-6125 Office
David R. Tribble     \   ,------------------'   \ +1-972-738-6111 Fax
http://www.beasys.com `-'  Dallas, TX 75248      `-----------------------
david.tribble@noSPAM.beasys.com            http://www.flash.net/~dtribble
Support the anti-Spam amendment, join at http://www.cauce.org/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]