# STL vector容器emplace_back和push_back的区别
这个问题可以讲是C++
面试问到的比较频繁的问题了,今天复习C++
类的默认生成的函数时,使用例子来说明下这两个函数的区别。
# C++的三法则和五法则
在C++11
以前,如果一个类需要析构函数,则一定需要拷贝构造函数和拷贝赋值操作符,譬如类包含指针成员时。这个是三法则。
C++11
后又添加了移动语义支持的移动构造函数和移动赋值操作符。因此扩充后称为五法则。
C++11
及以后,编译器会默认为类生成8个函数,分别是:
- 默认构造函数
- 默认析构函数
- 默认复制构造函数
- 默认赋值运算符重载函数
- 默认移动构造函数
- 默认移动赋值运算符重载函数
- 默认取地址函数
- 默认取地址const函数
# 比较emplace_back
和push_back
函数
push_back
和emplace_back
都是往vector
容器追加一个元素push_back
是复制或者移动一个对像到vector
中emplace_back
支持直接调用对像的构造函数,避免像push_back
那样的复制和移动。
代码比较:
先定义Object
类和包含vector
成员的MultObjects
:
class Object {
public:
Object() {
std::cout << "Object created.\n";
}
~Object() {
std::cout << "Object deleted.\n";
}
Object(const Object& obj)
{
std::cout << "Copy constructor.\n";
}
Object& operator=(const Object &obj) {
std::cout << "Copy Assignment.\n";
return *this;
}
Object(Object &&obj) {
std::cout << "Move Constuctor.\n";
}
Object& operator=(const Object &&obj) {
std::cout << "Move Assignment.\n";
return *this;
}
};
struct MultObjects
{
using Objs = std::vector<Object>;
Objs objects;
MultObjects(Objs objs) : objects{std::move(objs)}{}
};
注意,MultObjects
包含一个vector
成员,构造函数接受vector
类型值是通过move
来初始化的,这样可以直接将传入的值转化为右值并赋值给成员变量,避免了对像复制。
常规构造push_back
操作:
int main(void)
{
std::vector<Object> objects;
Object obj;
objects.push_back(obj);
MultObjects mult_objects(objects);
return 0;
}
以上程序运行的输出结果为:
Object created.
Copy constructor.
Copy constructor.
Object deleted.
Object deleted.
Object deleted.
可以看到对像被创建后复制了两次。
改进1:构造MutlObjects
对像时传入move
转化的值。
int main(void)
{
std::vector<Object> objects;
Object obj;
objects.push_back(obj);
MultObjects mult_objects(std::move(objects));
return 0;
}
程序编译运行后的输出:
# Object created.
# Copy constructor.
# Object deleted.
# Object deleted.
可见对像创建一次,复制一次,比改进前少复制了一次。
改进2:使用emplace_back
int main(void)
{
std::vector<Object> objects;
objects.emplace_back();
MultObjects mult_objects(std::move(objects));
return 0;
}
编译运行后程序的输出:
# Object created.
# Object deleted.
可以看到,使用emplace_back
后,没有复制也没有移动,直接调用了对像的构造函数。
# 总结
C++
标准库提供了emplace_back
函数,可以直接调用对像的构造函数,避免不必要的复制和移动。
# reference
← 模板中的实参推断和引用 externC →