简体   繁体   English

C ++ Lambdas,捕获,智能Ptrs和堆栈:为什么这有效?

[英]C++ Lambdas, Capturing, Smart Ptrs, and the Stack: Why Does this Work?

I've been playing around with some of the new features in C++11, and I tried to write the following program, expecting it not to work. 我一直在玩C ++ 11中的一些新功能,我试着编写以下程序,期望它不起作用。 Much to my surprise, it does (on GCC 4.6.1 on Linux x86 with the 'std=c++0x' flag): 令我惊讶的是,它(在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'
        ;
}

I was expecting 'from_ref' to be deleted when each execution of the returned lambda runs. 我希望每次执行返回的lambda时都会删除'from_ref'。 Here's my reasoning: once count_up_in_2s is run, from_ref is popped off the stack, yet because the returned lambda isn't neccessarily ran straight away, since it's returned, there isn't another reference in existence for a brief period until the same reference is pushed back on when the lambda is actually run, so shouldn't shared_ptr's reference count hit zero and then delete the data? 这是我的推理:一旦运行count_up_in_2s,from_ref就会从堆栈中弹出,但因为返回的lambda不是必须立即运行,因为它已经返回,所以在相同的引用之前,没有另一个引用存在很短的时间当lambda实际运行时推回,所以shared_ptr的引用计数不应该为零,然后删除数据?

Unless C++11's lambda capturing is a great deal more clever than I'm giving it credit for, which if it is, I'll be pleased. 除非C ++ 11的lambda捕获比我给它的功能更加聪明,如果是的话,我会很高兴的。 If this is the case, can I assume that C++11's variable capturing will allow all the lexical scoping/closure trickery a la Lisp as long as /something/ is taking care of dynamically allocated memory? 如果是这种情况,我可以假设只要/ something /处理动态分配的内存,C ++ 11的变量捕获将允许所有词法范围/闭包技巧la Lisp吗? Can I assume that all captured references will stay alive until the lambda itself is deleted, allowing me to use smart_ptrs in the above fashion? 我可以假设所有捕获的引用都将保留,直到lambda本身被删除,允许我以上述方式使用smart_ptrs吗?

If this is as I think it is, doesn't this mean that C++11 allows expressive higher-order programming? 如果这是我认为的那样,这是不是意味着C ++ 11允许表达高阶编程? If so, I think the C++11 committee did an excellent job =) 如果是这样,我认为C ++ 11委员会做得很好=)

The lambda captures from_ref by value, so it makes a copy. lambda按值捕获from_ref ,因此它会复制。 Because of this copy, the ref count is not 0 when from_ref gets destroyed, it is 1 because of the copy that still exists in the lambda. 由于此副本,当from_ref被销毁时,引用计数不为0,因为lambda中仍存在副本,因此它为1。

The following: 下列:

std::shared_ptr<int> from_ref(new int(from));
return [from_ref]() { return *from_ref += 2; };

is mostly equivalent to this: 大致相当于:

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);

where __uniqueLambdaType1432 is a program-globally unique type distinct from any other, even other lambda types generated by a lexically identical lambda expression. 其中__uniqueLambdaType1432是一个程序全局唯一类型,与其他任何类型都不同,甚至是由词法相同的lambda表达式生成的其他lambda类型。 Its actual name is not available to the programmer, and besides the object resulting from the original lambda expression, no other instances of it can be created because the constructor is actually hidden with compiler magic. 它的实际名称对程序员来说是不可用的,除了原始lambda表达式产生的对象外,不能创建它的其他实例,因为构造函数实际上是用编译魔术隐藏的。

from_ref is captured by value. from_ref按值捕获。

Your reasoning works if you substitute 如果你替换你的推理是有效的

return [from_ref]() { return *from_ref += 2; };

with

return [&from_ref]() { return *from_ref += 2; };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM