C++11 使用emplace添加到std::map时如何避免临时拷贝? #包括 #包括 使用名称空间std; 结构FooStruct { INTA; int b; }; int main() { 地图; 安放(0,{1,2}); 返回0; }

C++11 使用emplace添加到std::map时如何避免临时拷贝? #包括 #包括 使用名称空间std; 结构FooStruct { INTA; int b; }; int main() { 地图; 安放(0,{1,2}); 返回0; },c++11,stl,containers,emplace,C++11,Stl,Containers,Emplace,在防止临时复制方面,上述是否正确使用了emplace?上面的表格比你的好吗 #include <iostream> #include <map> using namespace std; struct FooStruct { int a; int b; }; int main() { map<int, FooStruct> fooMap; fooMap.emplace<int, FooStruct>(0, {1

在防止临时复制方面,上述是否正确使用了emplace?上面的表格比你的好吗

#include <iostream>
#include <map>
using namespace std;

struct FooStruct 
{
    int a;
    int b;
};

int main()
{
    map<int, FooStruct> fooMap;
    fooMap.emplace<int, FooStruct>(0, {1, 2});
    return 0;
}
fooMap.emplace(生成_对(0,{1,2}));
或者这些表单是否等效,并且它们都避免创建
FooStruct
的临时副本?

编辑:

在本线程中讨论的三种形式中,避免不必要副本的一种是@max66提出的形式。下面的代码及其输出捕获了这三种形式

fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2}));

上述代码(用Visual C++ 2015构建)生成以下输出:

#include <iostream>
#include <map>
using namespace std;

struct FooStruct 
{
    FooStruct() { cout << "FooStruct Default Constructor" << endl; }
    FooStruct(int a, int b) { this->a = a; this->b = b; cout << "FooStruct Parametrized Constructor" << endl; }
    int a;
    int b;
};

int main()
{
    map<int, FooStruct> fooMap;
    fooMap.emplace<int, FooStruct>(0, {1, 2});
    fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 }));
    fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4));
    return 0;
}
PS:我确实验证了上述输出中的每一行都对应于上面的单个emplace调用

如果您将“正确性”定义为简洁,您可能希望使用
std::map::insert
而不是像这样使用
std::map::emplace

FooStruct Parametrized Constructor
FooStruct Parametrized Constructor
FooStruct Parametrized Constructor
使用
emplace
时,您必须像示例中那样明确指定类型,或者在@max66建议的情况下,在
FooStruct
中明确定义构造函数:

fooMap.insert({0, {1, 2}});
(这也缺乏简洁性)

fooMap.insert({0,{1,2})不应与

fooMap.emplace(std::piecewise_construct,
    std::forward_as_tuple(0),
    std::forward_as_tuple(1, 2));
fooMap.emplace(生成_对(0,{1,2}));
正如@Swift所指出的,由于它还使用
std::pair
的move构造函数而创建的对象数量


如果“correct”的意思是“可编译并在运行时按预期工作”,那么您的两个示例都是正确的。

区别在于
make\u pair
使用
pair
的移动构造函数语义,而另一种方法是调用模板的构造函数。那么
fooMap.emplace(std::piecewise\u construction,std::forward\u as\u-tuple(0)呢,std::forward_as_tuple(1,2))
?@max66:你是说你的表格比上面提到的两个好吗?如果是的话,你能解释一下为什么会这样吗;我只是告诉你做同样事情的另一种方法;如果我没有错的话,它(大致)与第一个表单相同,但不需要显式的模板类型(在某些情况下可能很好)。@max66:+1用于消除指定模板类型的需要。我不同意“所有这三个表单[…]它们的等效性在于,它们都避免创建FooStruct的临时副本”。第一种和第三种形式也是如此;在第二种形式的情况下,据我所知,创建了一个pair
int
/
FooStruct
的临时副本,用于在映射中使用copy构造函数构造pair(移动构造函数,从C++11开始)。@max66:你说得对。我忘记了复制构造函数,显然得出了错误的结论。现在我们知道了,包含前向数组的形式是最好的解决方案。我将编辑我的答案以反映这一发现。好的,谢谢。我真正想要的是一个FooStruct的实例,它直接在映射的内存中构建<代码>fooMap.emplace(std::分段_构造,std::forward_as_元组(0),std::forward_as_元组(1,2))正好实现了这一点。其他形式,简明与否,涉及创建临时FooStruct实例,这是我想要避免的。请更新您的问题,以反映您正在寻找构造的最小数量的对象?此外,这种形式的
emplace
可能产生很少或没有运行时性能优势,因为编译器可以优化所有差异,您可能需要比较汇编。
fooMap.insert({0, {1, 2}});
fooMap.emplace(std::piecewise_construct,
    std::forward_as_tuple(0),
    std::forward_as_tuple(1, 2));
fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2}));