c++ lambda, capture, Smart Ptrs和Stack:为什么这样做?
C++ Lambdas, Capturing, Smart Ptrs, and the Stack: Why Does this Work?
我一直在摆弄c++ 11中的一些新特性,我试图编写以下程序,希望它不能工作。令我惊讶的是,它确实(在Linux x86上的GCC 4.6.1上使用'std=c++0x'标志):
#include <functional>
#include <iostream>
#include <memory>
std::function<int()> count_up_in_2s(const int from) {
std::shared_ptr<int> from_ref(new int(from));
return [from_ref]() { return *from_ref += 2; };
}
int main() {
auto iter_1 = count_up_in_2s(5);
auto iter_2 = count_up_in_2s(10);
for (size_t i = 1; i <= 10; i++)
std::cout << iter_1() << 't' << iter_2() << 'n'
;
}
我期望'from_ref'在每次执行返回的lambda运行时被删除。以下是我的推理:一旦count_up_in_2s运行,from_ref就会从堆栈中弹出,但是因为返回的lambda并不一定会立即运行,因为它返回了,所以在很短的一段时间内不会存在另一个引用,直到当lambda实际运行时,相同的引用被推回,所以shared_ptr的引用计数不应该为零,然后删除数据吗?
除非c++ 11的lambda捕获比我认为的要聪明得多,如果是的话,我会很高兴的。如果是这样的话,我是否可以假设c++ 11的变量捕获将允许所有的词法作用域/闭包技巧,就像Lisp一样,只要/something/正在处理动态分配的内存?我是否可以假设所有捕获的引用都将保持存活,直到lambda本身被删除,从而允许我以上述方式使用smart_ptrs ?
如果这是我认为是,这是不是意味着c++ 11允许表达高阶编程?如果是这样,我认为c++ 11委员会做得很好=)
lambda按值捕获from_ref
,因此它创建一个副本。因为这个拷贝,当from_ref
被销毁时,refcount不是0,它是1,因为拷贝仍然存在于lambda中。
以下内容:
std::shared_ptr<int> from_ref(new int(from));
return [from_ref]() { return *from_ref += 2; };
大致相当于:
std::shared_ptr<int> from_ref(new int(from));
class __uniqueLambdaType1432 {
std::shared_ptr<int> capture1;
public:
__uniqueLambdaType1432(std::shared_ptr<int> capture1) :
capture1(capture1) {
}
decltype(*capture1 += 2) operator ()() const {
return *capture1 += 2;
}
};
return __uniqueLambdaType1432(from_ref);
,其中__uniqueLambdaType1432
是程序全局唯一类型,区别于任何其他类型,甚至是由词法相同的lambda表达式生成的其他lambda类型。它的实际名称对于程序员来说是不可用的,并且除了由原始lambda表达式产生的对象之外,不能创建它的其他实例,因为构造函数实际上被编译器隐藏了。
from_ref按值捕获
如果你用
代替return [from_ref]() { return *from_ref += 2; };
return [&from_ref]() { return *from_ref += 2; };
- 为什么C++的文件 I/O 在读取文本文件时忽略初始空行?我怎样才能让它不这样做?
- 为什么在C++中对链表这样做?(像堆叠一样处理它们)
- C++ 如果在 if 为 true 之后运行,为什么还会这样做
- 为什么 arr[i++] 与 arr[i]++ 会这样做?
- std::字符串 's' 通过 '&s[0]' 转换为字符* - 如何/为什么这样做?
- C++子字符串为什么这样做
- C++循环、作用域和堆栈(为什么这样做?
- 为什么这样做?C中的字符指针
- C++中的字符串分配:为什么这样做
- 带有1个参数的C++2D数组索引(为什么这样做?)
- 为什么这样做?[C++;无效指针]
- 线程之间的Qt连接类型:为什么这样做
- 在派生类中同时分配多个字段-为什么这样做有效
- 为什么这样做?阵列访问不正常
- 迭代char**为什么这样做
- c++ lambda, capture, Smart Ptrs和Stack:为什么这样做?
- 在信号代码中将整数转换为函数指针-为什么这样做?
- 如果一个引用一旦被初始化为一个对象,它就不能被改变,为什么这样做呢?
- 回退可变构造函数-为什么这样做
- 访问类中的私有成员变量:为什么这样做