Использование t (* this) приводит к RuntimeError, тогда как t (std:: ref (* this) не
У меня есть следующий пример:
#include <iostream>
#include <functional>
struct Tmr {
typedef std::function<void(void)> Callback;
Callback cb;
Tmr(Callback cb_) :
cb( cb_ )
{
}
void timeout()
{
cb();
}
};
struct Obj {
struct Tmr t;
Obj() :
t( std::ref( *this ) )
{
}
void operator () ()
{
std::cout << __func__ << '\n';
}
};
int main(int argc, char *argv[])
{
Obj o;
o.t.timeout();
return 0;
}
Это работает отлично, но изначально у меня был конструктор Obj
как:
Obj() :
t( *this )
Это приводит к ошибке выполнения. Я предполагаю, что это связано с тем, что в моем обратном вызове хранится только ссылка на функцию-член, а не на объект для вызова элемента.
Я не понимаю, что делает std::ref
, когда я делаю Obj() : t(std::ref(*this))
и почему это заставляет программу работать. Может ли кто-нибудь пролить свет на то, что происходит и как оно работает?
Ответы
Ответ 1
Если вы не проходите по ссылке, вы копируете *this
до того, как t
был инициализирован - это означает, что вы копируете t
и его элемент обратного вызова до того, как они были инициализированы, что составляет undefined.
(И конструктор копирования std::function
, скорее всего, попытается скопировать то, на что указывает неинициализированный указатель, что и вызывает фактический сбой.)
Ответ 2
Сбой кода вызывается из-за копирования неинициализированного объекта обратного вызова. Вы можете увидеть последовательность событий ниже:
1. Copy constructor of Obj is called in t(*this)
2. Copy constructor of Tmr is called as t is a member of Obj
3. Copy constructor of Callback is called as cb is a member of Tmr
4. Execution fails while trying to copy from uninitialized Callback object.
Используя std:: ref, вы обойдете создание копии Obj; почему он не падает.