假设我们有一个带有某些对象的STL容器,并且这些对象可以将函数发布到队列中,以便稍后执行。但是在执行这些功能之前,将对容器进行修改,以使指向该对象的指针无效。让我用一个例子来说明:
#include <vector>
#include <functional>
class Class_A
{
public:
std::function<void()> getFunctionToRunLater()
{
return [this] () { somethingToDo(); moreThingsToDo(); };
// Returns a lambda function that captures the this pointer,
// so it can access the object's methods and variables.
}
void somethingToDo();
void moreThingsToDo();
}
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
pendingFunction();
}
Run Code Online (Sandbox Code Playgroud)
一切都很好,对吧?我们获得了对象要运行的功能,并经过一些逻辑后,我们执行了该功能。这表示将功能发布到队列中,并且它们执行队列中的所有功能。但是现在看一下这个:
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
vec.reserve(1000);
// This will surely reallocate the vector, invalidating all pointers.
pendingFunction();
// And now my program is going straight down to hell, right?
}
Run Code Online (Sandbox Code Playgroud)
我的假设正确吗?如果lambda根本不捕获任何东西,该程序在逻辑上是否仍会损坏?如果lambda没有捕获this指针,而是捕获了其他一些类字段,该怎么办?
是的,这个程序可能有问题。C++ 不会保护您免受无效指针的影响,并且正如您突出显示的那样,矢量中的对象可能会在矢量调整大小时移动地址,如果您尝试运行 lambda,这将导致问题。
如果不捕获this. 如果您尝试捕获对对象任何部分的引用或指针而不确定所指向的内存不会移动,您也会遇到问题。
谨慎是值得的,因为即使有错误,这样的程序也不能保证崩溃,因为即使矢量调整大小,旧数据可能仍然存在于内存中。因此,如果您尝试捕获this并且在运行时没有看到任何问题,并不意味着您的程序是正确的。
std::unique_ptr对于直接的解决方案,我会考虑使用智能指针类型之一(例如或 )在堆上分配对象std::shared_ptr。