今天在分析threadsafe_stack代码时发现自己对pop和push的具体实现原理以及注意事项还是有点疏漏,然后撸了一遍相关标准库代码,记录一下。
先说结论:
- pop与erase只是移动指针,不会删除内存,但是会调用该位置的析构函数,所以直接用变量引用这块内存是可以的,且不会出错emplace与push如果都是传入右值,那么实际使用上的区别就是emplace的不会调用析构函数,push进去的会调用析构函数move拷贝完了,原来的对象是会析构的
下图为vector< T>的pop_back的调用关系,其内部只是将M_impl._M_finish指针- -,然后调用该T的析构函数。并未完成该对象在该内存的清理,所以后续可以通过指针与引用对该地址进行操作。erase同理,内部函数调用比较类似。
emplace与push两者如果传入的是右值,则都是调用emplace_back
区别在于两者在placement_new那个点调用的构造函数不同,前者是调用构造函数,后者调用拷贝构造函数,所以push之后是需要调用析构,而emplace不需要
#include#include #include #include #include #include class Test { public: Test(int a):b(a){std::cout<<"Test "<b = t.b; t.b = 0; std::cout<<"Test&& "< v{1,2,3}; v.pop_back(); // v.erase(v.end()-1); std::cout<<"vector "< ts; std::stack a; a.push(1); // Test 1,Test&& 1, ~Test 0 a.emplace(2); // Test 2,这里没有后面两个,根据上面的分析可得知啦 Test& value = a.top(); //这里value引用了top(),虽然被pop了,但是其值还在 a.pop(); // ~Test 2 std::cout<<"value of pop is "<< value.b<<" and "< vector 2and 3 Test 1 Test&& 1 ~Test 0 Test 2 ~Test 2 value of pop is 2 and 1 ~Test 1



