2017-08-03 43 views
1
#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; 
} 

就防止临时副本而言,上述是否正确使用emplace?在上述形式大于如何在使用emplace添加到std :: map时避免临时副本?

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

更好或者是这些形式等同且二者避免造成FooStruct临时副本?

+0

区别在于'make_pair'使用'pair'的移动构造函数语义,而另一种方式是调用模板的构造函数。 – Swift

+0

fooMap.emplace(std :: piecewise_construct,std :: forward_as_tuple(0),std :: forward_as_tuple(1,2));'? – max66

+0

@ max66:你是说你的表单比上面提到的两个更好吗?如果是这样,你能解释为什么是这样吗? – DigitalEye

回答

0

编辑:

在此线程讨论的三种形式,即避免了不必要的拷贝之一是通过@ max66提出的形式。下面的代码,并且其输出捕获动作这三种形式

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

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

输出:

foo.emplace<int, FooStruct>(0, {1, 2}) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 })) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
FooStruct Copy Constructor 
fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4)) 
FooStruct Parametrized Constructor 

============

ORIGINAL(WRONG)

我很懒惰,在发布问题前没有深入挖掘。我现在看到所有这三种形式(第三种形式来自@ max66的评论)是相同的,因为他们三个都避免了创建临时副本FooStruct

#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; 
} 

上面的代码(用Visual C++ 2015内置)产生以下输出:

FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 

PS:我没有验证,在上述输出的每一行对应于一个单一布设呼叫以上

+1

我不同意这样一个事实,即“所有这三种形式都是相同的,因为它们三个都避免创建FooStruct的临时副本”。第一种和第三种形式都是如此;在第二种情况下,据我所知,创建了一对'int' /'FooStruct'的临时副本,用于在复制构造函数中构造映射对(移动构造函数,从C开始++ 11)。 – max66

+0

@ max66:你是对的。我忘了拷贝构造函数,显然得出了错误的结论。所以,现在我们知道您的涉及forward_as_tuple的表单是最佳解决方案。我将编辑我的答案以反映这一发现。 – DigitalEye

1

如果定义了“正确性”为简便起见,您可能需要使用std::map::insert,而不是std::map::emplace这样的:

fooMap.insert({0, {1, 2}}); 

随着emplace你必须显式地指定类型,比如在你的榜样或FooStruct通过@ max66建议的情况下,定义构造函数明确:

fooMap.emplace(std::piecewise_construct, 
    std::forward_as_tuple(0), 
    std::forward_as_tuple(1, 2)); 

(这也没啥简洁)。

fooMap.insert({0, {1, 2}});不应该在创建的对象的数量计算从

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

是不同的,因为它也使用了移动构造函数的std::pair作为@Swift指出。

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

+0

好的,谢谢。我真正所追求的是一个直接在地图内存中构建的FooStruct实例。 'fooMap.emplace(std :: piecewise_construct,std :: forward_as_tuple(0),std :: forward_as_tuple(1,2));'完成那个。其他形式,简洁与否,涉及创建一个临时FooStruct实例,这是我想避免的。 – DigitalEye

+0

您能否更新您的问题以反映您正在寻找构建的最小量的对象?此外,这种形式的'emplace'可能会产生很少的或没有运行时性能的好处,因为编译器可以优化所有差异,您可能需要比较汇编。 –

相关问题