Last Updated on 2022-11-29 by Clay
今天在刷題的時候,看到一位分享自己解題思路的網友,他的程式碼中所有宣告的 vector
陣列,全部都使用 emplace_back()
。那時候我可看不明白了,從我在大學上課開始寫時,老師都是教寫 push_back()
的啊?
實際上,emplace_back()
和 push_back()
都是在陣列的尾端加入一個元素(element),但實際上,兩者的性能是存在著差距的。
效能比較
網路上每次談到這個這兩種吧同方式效能的話題,都會看到以下這段範例的程式碼。
#include<iostream>
#include<vector>
using namespace std;
class MyClass {
private:
int x_ = 0;
int y_ = 0;
public:
MyClass(int x, int y) : x_(x), y_(y) {
cout << "Create class" << endl;
}
~MyClass() {
cout << "Destroy class" << endl;
}
// Copy constructor
MyClass(const MyClass& my_class) {
cout << "Copy Constructor Called" << endl;
x_ = my_class.x_;
}
// Move constructor
MyClass (MyClass&& my_class) noexcept {
cout << "Move Constructor Called" << endl;
x_ = move(my_class.x_);
}
};
int main() {
vector<MyClass> v;
v.reserve(2);
cout << "\n--- push_back ---" << endl;
v.push_back(MyClass(1, 2));
cout << "\n--- emplace_back ---" << endl;
v.emplace_back(1, 2);
cout << "\n--- Finished ---" << endl;
return 0;
}
Output:
--- push_back ---
Create class
Move Constructor Called
Destroy class
--- emplace_back ---
Create class
--- Finished ---
Destroy class
Destroy class
push_back()
是在容器(container)的尾端新增一個新的元素,接著再把要新增的『數值』移動、複製到該元素上。
emplace_back()
則是在容器的尾端直接建構(construct)新值的物件。所以,通常來說,使用 emplace_back()
會比 push_back()
來得更快。
那麼,我們是否就從此用 emplace_back()
來取代 push_back()
呢?
實際上,根據我的理解,存在著兩種情況最好不是輕易地使用 emplace_back()
來取代 push_back()
。
- 程式可能會需要在 C++11 以前的版本編譯,在這個版本以前並沒有
emplace_back()
- 我們不清楚建構函式(constructor)是哪種的情況
References 的連結中給出了一個清楚的說明:
std::vector<std::vector<int>> vec1, vec2;
// vec1.push_back(1000000); // compile error
vec2.emplace_back(1000000);
std::cout << "Vector Size = " << vec2.at(0).size() << std::endl;
Output:
Vector Size = 1000000
使用 push_back()
的時候,由於賦值會編譯錯誤,所以我們會收到編譯器的警告;然而在使用 emplace_back()
的時候,我們錯誤地建構了 1,000,000 個 vector —— 這是非常恐怖的記憶體開銷。
所以,要使用 emplace_back()
優化我們的程式時,也需要注意這些事項。
References
- https://yasenh.github.io/post/cpp-diary-1-emplace_back/
- std::vector<T,Allocator>::emplace_back - cppreference.com