emplace_back和push_back区别,以及vector内存变化

本文详细解析了C++中vector容器使用emplace_back与push_back时的行为差异,重点在于构造对象的方式及内存分配策略,对于理解C++内存管理和效率提升具有重要意义。

参考链接

void* operator new(size_t size)//重载operator new
{
 	cout << "vector size to: " << size/sizeof(int) << endl;
	 return malloc(size);
}
class test {
public:
 	test() :num(0) { cout << "default construct of " <<0<< endl; };
 	test(int a) :num(a) { cout << "assign construct of " <<a<<endl; };
 	test(test&& t) :num(t.num) { cout << "move construct of " << t.num<< 	endl; };
 	test(const test& t) :num(t.num) { cout << "copy construct of " << t.num<< endl; };//参数前必须加const否则会报错
 //如果不定义,会调用默认的拷贝构造 copy bitwise
 	~test()
 	{
 	 cout << "deconstruct" << endl;
	 };
	private:
 	int num;
};
int main()
{
 	vector<test> a;
 	//https://blog.youkuaiyun.com/LiQian06336/article/details/99181398
	 cout << "test" << sizeof(test) << endl;
	 cout << "vector size in memory: " << sizeof(a) << endl;
 	cout << "vector capacity: " << a.capacity() << endl;
 	a.push_back(1);
 	cout << "vector capacity: " << a.capacity() << endl;
 	a.emplace_back(2);
 	/cout << "vector capacity: " << a.capacity() << endl;
 	a.push_back(test(3));
	 cout << "vector capacity: " << a.capacity() << endl;
 	a.emplace_back(test(4));
 	cout << "vector capacity: " << a.capacity() << endl;
}

运行结果,

vector size to: 2
test4
vector size in memory: 16//刚开始会申请内存,用于存放指针,见main函数中的链接
vector capacity: 0//正式开始
assign construct of 1//push_back(1),先构造临时对象
vector size to: 1//再申请内存
move construct of 1//再调用移动构造
deconstruct//销毁临时对象
vector capacity: 1
vector size to: 2//empalce_back,先申请内存,申请的是原来大小的两倍,因为vector要扩容,扩容不是原地扩,而是新找一个更大的地方
assign construct of 2//再在申请得到的新内存上原地构造
copy construct of 1//因为vector的容量由1变为2,需要将原来地方的1拷贝过来
deconstruct//将原地方的1析构
vector capacity: 2
assign construct of 3//同1一样,构造临时对象
vector size to: 3//申请内存,扩容
move construct of 3//将3先移动到新的内存地方上
copy construct of 1//将剩余的移动过来
copy construct of 2
deconstruct//将临时对象3和原来的1和2析构
deconstruct
deconstruct
vector capacity: 3
assign construct of 4
vector size to: 4
move construct of 4//同3
copy construct of 1
copy construct of 2
copy construct of 3
deconstruct
deconstruct
deconstruct
deconstruct
vector capacity: 4
deconstruct
deconstruct
deconstruct
deconstruct

结论:

  • emplace_back和push_back区别在与以参数传入的时候
    ,emplace_back先申请内存,再原地构造,而push_back需要先构造临时对象。
  • 对临时对象的处理上,都依赖与是否存在移动构造,若有,则都优先调用移动构造
C++ 中,`std::vector` 提供了 `emplace_back` `push_back` 两种方法用于在容器末尾添加新元素。两者在功能性能上有显著区别,适用于不同场景。 ### 参数传递方式 `push_back` 接收一个已经构造好的元素对象,并将其复制或移动到容器中。如果传递的是左值,会调用拷贝构造函数;如果是右值,则会调用移动构造函数。例如: ```cpp std::vector<std::string> vec; std::string s = "hello"; vec.push_back(s); // 调用拷贝构造函数 vec.push_back("world"); // 调用移动构造函数 ``` `emplace_back` 则采用不同的策略,它接收构造元素所需的参数,并在容器内部直接构造新元素。这种机制称为“原地构造”,避免了额外的拷贝或移动操作。例如: ```cpp std::vector<std::string> vec; vec.emplace_back("hello"); // 直接构造std::string对象 ``` ### 性能差异 由于 `emplace_back` 在容器内部直接构造对象,它通常比 `push_back` 更高效。`push_back` 需要先在外部构造对象,然后将其复制或移动到容器中,这可能导致额外的开销。例如: ```cpp std::vector<std::pair<int, int>> vec; vec.push_back(std::make_pair(1, 2)); // 先构造pair,再移动到vector vec.emplace_back(1, 2); // 直接构造pair对象 ``` ### 类型转换安全性 尽管 `emplace_back` 在性能上有优势,但在某些情况下 `push_back` 更加安全。特别是当使用隐式类型转换时,`push_back` 会在编译时进行更严格的检查,避免潜在的错误。例如: ```cpp std::vector<std::unique_ptr<int>> vec; int a; vec.emplace_back(&a); // 编译通过,但存在安全隐患 vec.push_back(&a); // 编译失败,类型不匹配 std::vector<int8_t> vec2; int a = 1000; vec2.emplace_back(a); // 没有警告,但a超出int8_t范围 vec2.push_back(a); // 编译器发出-Wconversion警告 ``` ### 适用场景 - **使用 `emplace_back`**:当需要高性能且参数类型明确,不需要隐式类型转换时。 - **使用 `push_back`**:当需要编译时的安全检查,或者传递的参数需要隐式转换时。 综上所述,`emplace_back` `push_back` 各有优劣,选择时需根据具体场景权衡[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值