Group: comp.lang.c++
From: "Victor Bazarov"
Date: Tuesday, April 08, 2008 4:24 PM
Subject: Re: lifetime of const references...

Chris Thomasson wrote:
> Here is the code which should compile fine; program output and my
> question follows:
> ____________________________________________________________________
> #include
>
>
> namespace func_ptr {
> namespace sys {
> typedef void (callback_type) (void const* const);
>
> class base_pod {
> protected:
> callback_type* mp_callback;
>
> public:
> void execute() const {
> mp_callback(this);
> }
> };
>
> template
> class param_1 : public base_pod{
> T m_obj;
> T_mfptr m_mfptr;
> T_p1 m_p1;
>
> public:
> param_1(T obj, T_mfptr mfptr, T_p1 p1)
> : m_obj(obj), m_mfptr(mfptr), m_p1(p1) {
> mp_callback = sys_callback;
> std::printf("(%p)-param_1::param_1()\n",
> reinterpret_cast(this));
> }
>
> ~param_1() throw() {
> std::printf("(%p)-param_1::~param_1()\n",
> reinterpret_cast(this));
> }
>
> private:
> void callback() const {
> (m_obj->*(m_mfptr))(m_p1);
> }
>
> static void sys_callback(void const* const state) {
> static_cast(state)->callback();
> }
> };
> }
>
>
> typedef sys::base_pod const& handle;
>
>
> template
> sys::param_1
> create(T _this, T_mfptr mfptr, T_p1 p1) {
> return sys::param_1(_this, mfptr, p1);
> }
> }
>
>
> struct object {
> void func(int i) {
> std::printf("(%p)-object::func1(%d)\n",
> reinterpret_cast(this), i);
> }
> };
>
>
> struct holder {
> func_ptr::handle m_fptr;
> holder(func_ptr::handle fptr) : m_fptr(fptr) {}
> };
>
>
>
>
> int main() {
> object obj;
>
> {
> std::puts("Scope 1:\n");
> func_ptr::handle h(func_ptr::create(&obj, &object::func, 123));
> h.execute();
> }
>
> std::puts("\n\n--------------------------------------------");
>
> {
> std::puts("Scope 2:\n");
> holder h(func_ptr::create(&obj, &object::func, 123));
> h.m_fptr.execute();
> }
>
>
> /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
> std::puts("\n\n--------------------------------------------\n\
> Press to exit...");
> std::getchar();
> return 0;
> }
>
> ____________________________________________________________________
>
>
>
>
>
> Here is the output I get:
> ____________________________________________________________________
> Scope 1:
>
> (0022FF30)-param_1::param_1()
> (0022FF5F)-object::func1(123)
> (0022FF30)-param_1::~param_1()
>
>
> --------------------------------------------
> Scope 2:
>
> (0022FF30)-param_1::param_1()
> (0022FF30)-param_1::~param_1()
> (0022FF5F)-object::func1(123)
>
>
> --------------------------------------------
> Press to exit...
>
> ____________________________________________________________________
>
>
>
>
> I am wondering why the const reference in 'Scope 2' (e.g.,
> holder::m_fptr) is getting destructed _before_ the call to
> 'h.m_fptr.execute()'? I thought the output should be identical to
> that of 'Scope 1'... What exactly am I doing wrong here? I am
> screwing something up somewhere... What can be done to resolve this
> issue?
>
> Yikes! ;^(...

The difference is that in Scope 1 you're initialising a local variable
that has a reference to const type directly by a temporary. The life
of that temporary is extended to the end of the scope, but in Scope 2
you're initialising the reference to const that itself is an argument
to the c-tor, so the life of the temporary is limited to the expression
that is used to initialise the 'h' object. The member 'm_fptr' of the
'h' object (it's a reference that you copy-initialise from the argument)
becomes invalid as soon as the initialisation is complete. The temp
object is destroyed. A call to .execute() has undefined behaviour.

Here is the model of your code, in simpler terms:

#inlcude
struct A {
void foo() { std::cout << "A::foo\n"; }
};

struct B {
A const &a;
B(A const &a) : a(a) {}
};

A makeA() { return A(); }

int main() {
{ // Scope 1
A const& ra(makeA());
ra.foo();
}

{ // Scope 2
B b(makeA()); // problem - the temporary dies here
b.a.roo(); // and here you're trying to use it
}
}

In my Scope 1 'ra' is a reference to the temporary object. In
my Scope 2 'b.a' is a reference to the temporary object, but it
is not initialised _directly_ by binding to the temporary, it's
_copy-initialised_ with a _temporary_ reference to A, which in
turn is bound to the temporary. The lifetime of the temporary
'A' in Scope 2 _would_ be extended if the reference (the argument
to the B's c-tor) survived beyond the initialisation expression.
It does not.

HTH

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask


Safety Articles | Usenet Groups | 20lbs in 30 days