C++11 lambda 无法访问引用
C++11 lambda cannot access reference
我在C++中遇到lambda函数的问题:我正在尝试定义一个异步加载器,该加载器填充给定字符串列表作为输入的对象数组。
代码看起来像这样(不完全是,但我希望你明白这个想法(:
void loadData() {
while (we_have_data()) {
std::string str = getNext();
array.resize(array.size() + 1);
element &e = array.back();
tasks.push_back([&, str] () {
std::istringstream iss(str);
iss >> e;
}
}
for (auto task: tasks) {
task();
}
}
最后,当我扫描任务列表并执行它们时,应用程序在第一次访问 lambda 中的变量 e 时崩溃。如果我在调试器中运行,我可以在对象 e 本身中找到正确的值。我做错了什么,但我真的不明白是什么。
你拿着一个悬空的引用。 当你这样做时
tasks.push_back([&, str] () {
std::istringstream iss(str);
iss >> e;
}
通过引用捕获array.back()
返回的元素,因为对e
的引用实际上是对e
引用的任何内容的引用。 不幸的是,resize
是在 while 循环中调用的,因此当调整array
大小时,对back()
的引用将失效,您现在引用的对象不再存在。
element& e
的作用域是while
循环。
在 while
循环的每次迭代之后,您都有 lambda 函数,其中包含对不同e
的捕获引用,这些函数都超出了范围。
你捕获e
(又名。 创建 lambda 时array.back()
( "by-reference",随后调整array
的大小(可能重新分配(,会留下悬而未决的引用,进而在您尝试访问此悬空引用时导致错误。在数组经过调整大小(和重新分配(后,任何尝试(不限于 lambda(通过先前分配的引用访问array
中的元素都会导致"悬空引用"问题。
另一种选择...与其使用这两个循环,不如立即在while
循环中执行任务,并放弃悬而未决的引用并尝试使基于指针或迭代器的替代方案正常工作。
进一步的替代...如果array
中的元素可以共享,则可以使用std::shared_ptr
解决方案,但需要注意的是按值捕获shared_ptr
元素,从而确保 Lambda 在调整大小时与array
共享这些元素的所有权。
这个想法的样本...
void loadData() {
while (we_have_data()) {
std::string str = getNext();
array.resize(array.size() + 1);
std::shared_ptr<element> e = array.back();
tasks.push_back([e, str] () {
std::istringstream iss(str);
iss >> *e;
}
}
for (auto task: tasks) {
task();
}
}
你在这里有两次罢工。
首先,您正在捕获对迭代器的引用,该向量可能会被调整大小并因此重新定位。
其次,您正在捕获对超出范围的局部(堆栈(变量的引用。在循环中,编译器可能每次都对"e"使用相同的内存位置,因此所有引用都将指向相同的堆栈位置。
更简单的解决方案是存储元素编号:
while (we_have_data()) {
std::string str = getNext();
size_t e = array.size();
array.resize(e + 1);
tasks.push_back([&, e, str] () {
std::istringstream iss(str);
iss >> array[e];
}
}
如果您有 C++14 并且字符串很长,您可能需要考虑:
tasks.push_back([&, e, str{std::move(str)}] () {
所有这些都假设数组在任务运行时不会经过进一步的操作或超出范围。
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 通过引用访问矢量元素是否会降低C++的空间复杂性?
- 形成对对象的引用是否构成访问?
- 错误:未定义对"静脉类型信息::电池访问"的引用
- 如何在 c++ 中通过基类引用访问派生类的对象?
- 项目引用上的QT访问冲突
- 通过引用传递时访问std::vector的元素
- 是否可以在堆中分配向量,但通过引用进行访问
- 如何通过引用或指针访问二维矢量
- 访问对象的取消引用值的语法
- 为什么引用类型在使用临时对象访问时是左值
- 如何访问对象的成员变量的取消引用值
- 如果包含引用成员的类中缺少原始变量,为什么它仍然可以访问?
- 为什么访问我的引用捕获变量会导致我的 lambda 函数出现段错误?
- 如何从派生类访问引用成员变量?
- 无法访问引用 C++ 后面的信息
- 在引用向量时使用访问器进行迭代C++
- 访问由 void 指针引用的结构的成员
- 访问引用变量会终止程序
- C++11 lambda 无法访问引用