最近在寫一段代碼的時候,忽然很好奇C++11中對push_back有沒有什麼改進以增長效率,上網搜了一些資料,發現果真新增了emplace_back方法,比push_back的效率要高不少。ios
首先,寫了一個類用於計時,函數
//time_interval.h #pragma once #include <iostream> #include <memory> #include <string> #ifdef GCC #include <sys/time.h> #else #include <ctime> #endif // GCC class TimeInterval { public: TimeInterval(const std::string& d) : detail(d) { init(); } TimeInterval() { init(); } ~TimeInterval() { #ifdef GCC gettimeofday(&end, NULL); std::cout << detail << 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000 << " ms" << endl; #else end = clock(); std::cout << detail << (double)(end - start) << " ms" << std::endl; #endif // GCC } protected: void init() { #ifdef GCC gettimeofday(&start, NULL); #else start = clock(); #endif // GCC } private: std::string detail; #ifdef GCC timeval start, end; #else clock_t start, end; #endif // GCC }; #define TIME_INTERVAL_SCOPE(d) std::shared_ptr<TimeInterval> time_interval_scope_begin = std::make_shared<TimeInterval>(d)
使用方法就是在做用域中使用宏TIME_INTERVAL_SCOPE(d),d爲打印用的字符串,輸出做用域的耗時狀況。ui
其次,看一下如今push到vector的5種方法的耗時狀況對比:spa
#include <vector> #include <string> #include "time_interval.h" int main() { std::vector<std::string> v; int count = 10000000; v.reserve(count); //預分配十萬大小,排除掉分配內存的時間 { TIME_INTERVAL_SCOPE("push_back string:"); for (int i = 0; i < count; i++) { std::string temp("ceshi"); v.push_back(temp);// push_back(const string&),參數是左值引用 } } v.clear(); { TIME_INTERVAL_SCOPE("push_back move(string):"); for (int i = 0; i < count; i++) { std::string temp("ceshi"); v.push_back(std::move(temp));// push_back(string &&), 參數是右值引用 } } v.clear(); { TIME_INTERVAL_SCOPE("push_back(string):"); for (int i = 0; i < count; i++) { v.push_back(std::string("ceshi"));// push_back(string &&), 參數是右值引用 } } v.clear(); { TIME_INTERVAL_SCOPE("push_back(c string):"); for (int i = 0; i < count; i++) { v.push_back("ceshi");// push_back(string &&), 參數是右值引用 } } v.clear(); { TIME_INTERVAL_SCOPE("emplace_back(c string):"); for (int i = 0; i < count; i++) { v.emplace_back("ceshi");// 只有一次構造函數,不調用拷貝構造函數,速度最快 } } }
vs2015 release下編譯,運行結果:code
push_back string:327 ms
push_back move(string):213 ms
push_back(string):229 ms
push_back(c string):215 ms
emplace_back(c string):122 ms內存
第1中方法耗時最長,緣由顯而易見,將調用左值引用的push_back,且將會調用一次string的拷貝構造函數,比較耗時,這裏的string還算很短的,若是很長的話,差別會更大作用域
第二、三、4中方法耗時基本同樣,參數爲右值,將調用右值引用的push_back,故調用string的移動構造函數,移動構造函數耗時比拷貝構造函數少,由於不須要從新分配內存空間。字符串
第5中方法耗時最少,由於emplace_back只調用構造函數,沒有移動構造函數,也沒有拷貝構造函數。get
爲了證明上述論斷,咱們自定義一個類,並在普通構造函數、拷貝構造函數、移動構造函數中打印相應描述:string
#include <vector> #include <string> #include "time_interval.h" class Foo { public: Foo(std::string str) : name(str) { std::cout << "constructor" << std::endl; } Foo(const Foo& f) : name(f.name) { std::cout << "copy constructor" << std::endl; } Foo(Foo&& f) : name(std::move(f.name)){ std::cout << "move constructor" << std::endl; } private: std::string name; }; int main() { std::vector<Foo> v; int count = 10000000; v.reserve(count); //預分配十萬大小,排除掉分配內存的時間 { TIME_INTERVAL_SCOPE("push_back T:"); Foo temp("ceshi"); v.push_back(temp);// push_back(const T&),參數是左值引用 //打印結果: //constructor //copy constructor } v.clear(); { TIME_INTERVAL_SCOPE("push_back move(T):"); Foo temp("ceshi"); v.push_back(std::move(temp));// push_back(T &&), 參數是右值引用 //打印結果: //constructor //move constructor } v.clear(); { TIME_INTERVAL_SCOPE("push_back(T&&):"); v.push_back(Foo("ceshi"));// push_back(T &&), 參數是右值引用 //打印結果: //constructor //move constructor } v.clear(); { std::string temp = "ceshi"; TIME_INTERVAL_SCOPE("push_back(string):"); v.push_back(temp);// push_back(T &&), 參數是右值引用 //打印結果: //constructor //move constructor } v.clear(); { std::string temp = "ceshi"; TIME_INTERVAL_SCOPE("emplace_back(string):"); v.emplace_back(temp);// 只有一次構造函數,不調用拷貝構造函數,速度最快 //打印結果: //constructor } }
結論:在C++11狀況下,果斷用emplace_back代替push_back