我想弄清楚为什么下面的代码会中断。在lambda表达式中调用objects->pop();
后,Visual Studio调试时objects
的内存地址变为0xfeeefeee。我可以通过在 pop 之前执行 auto p = objects;
来解决这个问题,然后在第二行使用 p
而不是 objects
lambda 。但是,我必须在这里遗漏一些基本的东西。
class Obj
{
public:
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
objects->pop(); // objects' address changed after this executes
objects->push(shared_ptr<Obj>(new Obj(objects)));
};
}
function<void(void)> fun;
};
int main()
{
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
objects.top().get()->fun();
return 0;
}
最佳答案
您正在观察的是 undefined behavior .
捕获的内存objects
调用 objects->pop();
时释放变量占用一个很好的提示是它更改为的值: 0xFEEEFEEE
.这个魔数(Magic Number)表示释放的内存。
让我们分析一下会发生什么。
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
A stack
与 shared_ptr
的被创建。推到它上面的是一个新的 Obj
实例,其构造函数参数是指向我们的 stack
的指针.
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
/* ... */
};
}
A function
对象被分配了一个 lambda,它捕获了 objects
争论。
objects.top().get()->fun();
调用函数对象:
objects->pop(); // objects' address changed after this executes
objects
的栈顶元素指向,是Obj
fun
的实例对象所属。通过弹出它,shared_ptr
的唯一(也是最后一个)实例持有对它的引用超出范围并释放它使用的内存。这包括捕获的指向 objects
的指针.在调试版本中 HeapFree
将其设置为 0xFEEEFEEE
.在发布版本中,任何事情都可能发生。在此之后,您将引用已释放的内存,这是未定义的行为。
关于C++ lambda 表达式 : captured pointer to STL container changing address after pop?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23008198/