【问题标题】:Lambda reinitialize vector - why does it work?Lambda 重新初始化向量 - 为什么它有效?
【发布时间】:2015-04-20 20:21:25
【问题描述】:

为什么下面会编译?

vector<int> vec;

auto lambda = [ vec (move(vec)) ]() {  //??      
};

如何使用 vec (move(vec)) 重新初始化已分配的 vec 变量?这不调用移动构造函数吗?

如果我写:

vector<int> vec;
vec (move(vec));

这是无效的

【问题讨论】:

  • 在 msvc2013 中你不能这样做。你用什么编译器?
  • (当两个编译器在标准代码上说不同的东西时,几乎总是 MSVC 是错误的,而 GCC 是正确的)
  • vec(move(vec)) 等价于vec.operator()(move(vec))。可能您的意思是移动构造:vector&lt;int&gt; v2(move(vec)); 或移动分配:v2 = move(vec)
  • @myaut 它在我写的最后一个 sn-p 中,它是第一个移动构造(根据我从答案中得到的)

标签: c++ lambda c++14


【解决方案1】:

这称为 init-capture。它声明了一个隐藏上述vec 的新变量。它用于捕获 lambda 表达式中的仅移动类型:

init-capture 的行为就好像它声明并显式捕获了“auto init-capture ;”形式的变量 其声明区域是 lambda 表达式的复合语句,[..]

更多关于cppreference的信息。

【讨论】:

  • 有趣.. 调用 lambda 时谁拥有资源?我想只有 lambda 捕获的变量(因为另一个已经移动了它的数据),对吧?
  • @Albert vec 被移入初始化捕获,其生命周期受 lambda 的声明区域约束,因此现在拥有资源的是 lambda。
【解决方案2】:

这是一个没有进入 C++11 而是 C++14 的更改,我们可以从 N3610 中看到基本原理:

C++11 lambda 不支持移动捕获。对于 C++11,至少有两个被拒绝的 NB cmets,第一个是 CD1 上的 JP9,第二个是 FCD 上的 FI8。 FI8 引用了 Roshan Naik 的核心反射器消息,Roshan 解释说,能够移动捕获容器和其他复制成本高昂的对象将非常有用。此外,像 iostreams(尤其是 stringstreams)和 unique_ptrs 这样的只移动类型不能在不包装它们的情况下被捕获。移动语义和 lambda 之间缺乏合作在 2012 年波特兰的 Evolution 工作组中被简要讨论为“完成 C++11”的潜在扩展之一。不幸的是,时间安排上的冲突和时间的缺乏阻碍了为这种扩展制定措辞建议;本文试图解释预期的设计

措辞由N3648介绍:

对于每个 init-capture,都有一个由 init-capture 的标识符在闭包类型中声明。这 member 不是位域且不可变。该成员的类型 对应于假设变量声明的类型 形成“auto init-capture ;”,除了变量名(即 init-capture 的标识符)被唯一标识符替换。 [ 注意:这会启用初始化捕获,例如 "x = std::move(x)";第二 “x”必须绑定到周围上下文中的声明。 ——尾注 ] 初始化捕获没有捕获任何实体。内 lambda-expression 的 lambda-declarator 和复合语句, init-capture 中的标识符隐藏了任何同名的声明 在包含 lambda 表达式的范围内。 [ 例子:

int x = 4;
auto y = [&r = x, x = x+1]()->int {
            r += 2;
            return x+2;
         }();  // Updates ::x to 6, and initializes y to 7.

--结束示例]

C++14 标准草案N3936 中的措辞发生了变化,尽管看起来像是格式化和清理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 2017-12-07
    相关资源
    最近更新 更多