C++ 中emplace_back和push_back差异
生活随笔
收集整理的這篇文章主要介紹了
C++ 中emplace_back和push_back差异
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
最近看rocskdb源碼,發現了大量的設計模式和C++高級特性,特此補充一下,鞏固基礎。
問題描述
其中關于動態數組的元素添加,代碼中基本將push_back拋棄掉了,全部替換為emplace_back進行元素的添加。
看了一下官網描述:
原來的push_back 一個右值元素的時候 過程分為如下幾步:
- 使用右值數據類型的構造函數 構造一個臨時對象
- 調用拷貝構造函數將臨時對象放入 容器中
- 釋放臨時對象
可以看到以上的三個步驟,臨時對象的資源就沒有用到,而且還多了一次拷貝構造的過程,效率大大降低
后來真針對push_back的優化是引入了右值引用,即在構造出臨時對象之后直接調用轉移構造函數std::move()的形態,將臨時對象的值和地址全部轉移到容器,臨時對象直接就變為空了。
所以c++11的emplace_back是在以上基礎上進一步優化的,在容器的尾部添加元素,而這個元素是原地構造的,不需要調用拷貝構造函數和轉移構造函數了。
測試
測試代碼如下:
#include <iostream>
#include <vector>
#include <unistd.h>using namespace std;class Test {
private:int num;public:Test(int x):num(x){std::cout << "constructed\n";}/*拷貝構造函數*/Test(const Test &obj) {num = obj.num;std::cout << "copy constructed\n";}/*C++11 支持的 轉移構造函數*/Test (Test &&obj) {num = std::move(obj.num);std::cout << "moved constructed\n";}};int main() {vector<Test> arr;vector<Test> t_arr;std::cout << "push_back : Test(1)\n";arr.push_back(1);std::cout << "emplace_back : Test(1)\n";t_arr.emplace_back(1);return 0;
}
輸出如下:
push_back : Test(1)
constructed
moved constructed
emplace_back : Test(1)
constructed
很明顯,這里使用push_back進行了兩次構造(臨時對象的構造 和 轉移構造函數),而empalce_back僅僅構造了臨時對象。
所以emplace_back的性能會優于push_back。
源碼分析
以下源碼是boost庫的最新源代碼,所以push_back的實現也是經過優化的(將拷貝構造函數的實現變更為轉移構造函數)
關于empalce_back的boost源碼實現過程如下:
template <class _Tp, class _Allocator>
template <class... _Args>
inline
#if _LIBCPP_STD_VER > 14
typename vector<_Tp, _Allocator>::reference
#else
void
#endif
vector<_Tp, _Allocator>::emplace_back(_Args&&... __args)
{if (this->__end_ < this->__end_cap()){__RAII_IncreaseAnnotator __annotator(*this);/*傳入可變長參數模版forward進行對象構造,并添加到this代表的容器的末尾*/__alloc_traits::construct(this->__alloc(),_VSTD::__to_raw_pointer(this->__end_),_VSTD::forward<_Args>(__args)...);__annotator.__done();++this->__end_;}else__emplace_back_slow_path(_VSTD::forward<_Args>(__args)...);
#if _LIBCPP_STD_VER > 14return this->back();
#endif
}
push_back的源碼如下:
template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
void
vector<_Tp, _Allocator>::push_back(value_type&& __x)
{if (this->__end_ < this->__end_cap()){/*構造容器指針*/__RAII_IncreaseAnnotator __annotator(*this);/*使用move 的轉移構造函數*/__alloc_traits::construct(this->__alloc(),_VSTD::__to_raw_pointer(this->__end_),_VSTD::move(__x));__annotator.__done();++this->__end_;}else__push_back_slow_path(_VSTD::move(__x));
}
總結
以上是生活随笔為你收集整理的C++ 中emplace_back和push_back差异的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 钢铁侠在飞机上变身是哪一部?
- 下一篇: Rocksdb 内存“不释放”问题 分析