Ах, он должен винить деструктор временного - Bang(100500)
, который возвращает форму GetBang
, равен prvalue
и имеет temporary object lifetime
.
[this]
будет храниться как ссылка на *this
, например:
class Lambda
{
public:
void operator()() const
{
//output
}
private:
Bang& bang;
public:
Lambda(Bang& bang) : bang{bang}
{
}
} lambda{*this};
...
m_foo = lambda;
Поскольку здесь нет RVO
, поэтому временный Bang(100500)
сначала будет присвоен b
, а затем уничтожен.
Custorm operator()
, constructor
и destructor
для вывода некоторой информации:
#include <iostream>
#include <functional>
using namespace std;
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
std::cout << "Bang(int i = 0) m_val address is " << &m_val << '\n';
class Lambda
{
public:
void operator()() const
{
std::cout << "operator() m_val address is " << &bang.m_val << '\n';
std::cout << bang.m_val << std::endl;
}
private:
Bang &bang;
public:
Lambda(Bang &bang) : bang{bang}
{
}
} lambda{*this};
m_foo = lambda;
}
~Bang()
{
std::cout << "~Bang()\n";
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main()
{
Bang b;
b = GetBang();
b.Foo();
return 0;
}
live demo
Выход:
Bang(int i = 0) m_val address is 0x7ffd202c48b0
Bang(int i = 0) m_val address is 0x7ffd202c48e0
~Bang()
operator() m_val address is 0x7ffd202c48e0
-1
~Bang()
показывает:
dtor
будет вызыватьсяперед выводом, это означает, что временный объект был уничтожен.Адрес m_value
не меняется.
Двое гарантировали, что мы все еще получаем доступ к временному m_value
из b
m_foo()
.
Для доступа к объекту, который был уничтожен, должно быть Неопределенное поведение , но предупреждения и ошибки не требуются.
Обновление
Чтобы решить проблему, есть два решения:
- Как @ Killzone Kid указывает,захват с инициализатором:
[bang = *this]
.Для этого требуется c ++ 14. - Более простой способ захвата текущего объекта путем копирования:
[*this]
.Это требует c ++ 17.live demo