C++ STL中的 emplace
程序员文章站
2022-03-21 16:36:43
...
英文释义(以前还真的很少用到这个单词,但是经常在键入empty()函数的时候冒出来):
emplace
英 [ɪm'pleɪs] 美 [ɪm'pleɪs]
v. 放列,安置,安放;
相对于insert、push、push_back系列先构造临时变量再复制到目标位置,emplace直接在目标位置上构造了。而且emplace支持“变参模板”,也就是说,如果它的实例类的构造函数有多个参数,emplace也支持对应个数的参数,而且对于显式构造函数,也能直接传参数。
比如这个类,接受一个int型的构造函数
class EmplaceClass {
int num;
public:
/*explicit */EmplaceClass(int x = 0) :num(x) { cout << "Constructed.\n"; }
EmplaceClass(const EmplaceClass& from) :num(from.num) { cout << "Copied.\n"; }
~EmplaceClass() {/* cout << "Destructed.\n"; */}
};
在主函数函数中调用时的测试,为了避免vector增长后会复制,所以分别各自的vector进行push_back和emplace_back
vector<EmplaceClass> ecTest,pbTest;
cout << "Now emplace one element:" << endl;
ecTest.emplace_back(1);
cout << "Now push back one element:" << endl;
pbTest.push_back(1);
输出为
Now emplace one element:
Constructed.
Now push back one element:
Constructed.
Copied.
emplace操作少了一次复制
当构造函数为显示时
class EmplaceClass {
int num;
public:
explicit EmplaceClass(int x = 0) :num(x) { cout << "Constructed.\n"; }
EmplaceClass(const EmplaceClass& from) :num(from.num) { cout << "Copied.\n"; }
~EmplaceClass() {/* cout << "Destructed.\n"; */}
};
编译器就会报错
加入移动构造函数
class EmplaceClass {
int num;
string str;
public:
/*explicit*/ EmplaceClass(int x = 0,string s="") :num(x) ,str(move(s)){ cout << "Constructed.\n"; }
EmplaceClass(const EmplaceClass& from) :num(from.num),str(move(from.str)) { cout << "Copied.\n"; }
EmplaceClass(EmplaceClass && from) :num(from.num), str(move(from.str)) { cout << "Moved.\n"; }
~EmplaceClass() {/* cout << "Destructed.\n"; */}
};
vector<EmplaceClass> ecTest,pbTest;
cout << "Now emplace one element:" << endl;
ecTest.emplace_back(1,"a");
cout << "Now push back one element:" << endl;
//EmplaceClass ec(1, "a");
//pbTest.push_back(ec);//左值引用
pbTest.push_back({ 1,"a"});//右值引用
输出为
Now emplace one element:
Constructed.
Now push back one element:
Constructed.
Moved.
其实看看C++17里面push_back函数的源码,就知道原因了:
void push_back(const _Ty& _Val)
{ // insert element at end, provide strong guarantee
emplace_back(_Val);
}
void push_back(_Ty&& _Val)
{ // insert by moving into element at end, provide strong guarantee
emplace_back(_STD move(_Val));
}
相当于先构建一个左值或者右值引用_Val,再调用emplace_back。