【问题标题】:Lambda as an argument to std::vector::emplace_backLambda 作为 std::vector::emplace_back 的参数
【发布时间】:2018-04-27 16:55:07
【问题描述】:

我遇到了将 lambda 作为参数传递给 emplace_back 的代码,这让我很困惑。所以我写了一个小测试来验证这样的语法:

struct A
{
    int a;
    A(){cout<<"constructed"<<endl;}
    A(const A& other){a = other.a; cout<<"copied"<<endl;}
    A(const A&& other){a = other.a; cout<<"moved"<<endl;}
};

int main()
{
   vector<A> vec;
   vec.emplace_back(
       []{A a;
       a.a = 1;
       return a;   
       }());

   A a2;
   a2.a = 2;
   vec.emplace_back(std::move(a2));

  return 0;
}

我有两个问题: 1) 有人可以澄清如何将 lambda 作为参数传递给 emplace_back 吗?过去我只看到构造函数参数被传递给 emplace 。 2)输出是:

constructed
moved
constructed
moved
copied

最后一个副本来自哪里?为什么这两种方法不等价。

【问题讨论】:

  • 这是被放置的 lambda 的结果。注意 lambda 末尾的 }()); 中额外的 ()。立即计算 lambda。
  • 是的,但这是否意味着我可以调用emplace_back中的任何函数,只要返回可以传递给构造函数?
  • 是的。评估参数时,如果表达式是函数调用,则将使用该函数的结果。这就是所有功能的工作方式,而不仅仅是emplace_back。请务必了解emplace_back 永远不会看到该功能。它只会看到结果。
  • 考虑阅读good c++ book

标签: c++ stl stdvector


【解决方案1】:

有人可以澄清如何将 lambda 作为参数传递给 emplace_back 吗?

您没有传递 lambda。相反,您传递调用 lambda 的结果

最后一个副本来自哪里?

它来自向量。当a2 插入vec 时,会发生重新分配,重新分配内存并将旧内存中的对象复制到新内存。

如果将移动构造函数指定为noexcept,即

A(const A&& other) noexcept {a = other.a; cout<<"moved"<<endl;}

那么std::vector将在重新分配时移动对象而不是复制,你可以看到最后一个副本变成了移动。

【讨论】:

  • 感谢您对 realloc 的了解。就是这样。但是, noexcept 并没有改变行为。我将复制构造函数标记为 = delete,以使“已复制”变为“已移动”。为什么你会期望 noexcept 改变这一点?
  • @Haytham 见this answer。您使用的是 VS2015 或更早版本吗?
  • 谢谢,很有帮助!
【解决方案2】:

注意 lambda 定义后的 (),它调用了 lambda。这段代码等价于:

int main()
{
    auto make_a = []()
    {
        A a;
        a.a = 1;
        return a;
    };

    vector<A> vec;
    vec.emplace_back(make_a());

    // ...
}

由于 lambda 具有空捕获,因此等效于:

A make_a()
{
    A a;
    a.a = 1;
    return a;
}

int main()
{
    vector<A> vec;
    vec.emplace_back(make_a());

    // ...
}

【讨论】:

  • 感谢您的澄清。这很有帮助。
猜你喜欢
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 2015-01-15
  • 1970-01-01
  • 2017-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多