Re: lifetime of const references...
Chris Thomasson wrote:
Here is the code which should compile fine; program output and my
question follows:
____________________________________________________________________
#include <cstdio>
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<typename T, typename T_mfptr, typename T_p1>
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<void*>(this));
}
~param_1() throw() {
std::printf("(%p)-param_1::~param_1()\n",
reinterpret_cast<void*>(this));
}
private:
void callback() const {
(m_obj->*(m_mfptr))(m_p1);
}
static void sys_callback(void const* const state) {
static_cast<param_1 const*>(state)->callback();
}
};
}
typedef sys::base_pod const& handle;
template<typename T, typename T_mfptr, typename T_p1>
sys::param_1<T, T_mfptr, T_p1>
create(T _this, T_mfptr mfptr, T_p1 p1) {
return sys::param_1<T, T_mfptr, T_p1>(_this, mfptr, p1);
}
}
struct object {
void func(int i) {
std::printf("(%p)-object::func1(%d)\n",
reinterpret_cast<void*>(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 <ENTER> 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 <ENTER> 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 <iostream>
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