[英]Why is there no emplace or emplace_back for std::string?
[英]Why emplace_back does matter?
#include <iostream>
#include <vector>
struct T{
T(){
std::cout << "Constructor\n";
}
~T(){
std::cout << "Destructor\n";
}
};
int main() {
std::vector<T> vec;
vec.push_back(T());
vec.push_back(T());
return 0;
}
輸出為:
(1)Constructor
(2)Destructor
(3)Constructor
(4)Destructor
(5)Destructor
(6)Destructor
(7)Destructor
為什么有如此多的節制調用? 我看到:
(1)構建臨時對象temp1
(2)破壞temp1
(3)構造臨時對象temp2
(4)破壞temp2
然后,它被稱為temp1和temp 2的復制構造函數或move構造函數。因此,(5)和(6)很清楚。 但是(7)呢?
讓我們擴展一下結構:
struct T {
T() {
std::cout << "Constructor\n";
}
T(const T&) {
std::cout << "Copy Constructor\n";
}
T(T&&) {
std::cout << "Move Constructor\n";
}
~T() {
std::cout << "Destructor\n";
}
};
並分別調用push_back
方法:
vec.push_back(T()); // 1
std::cout << "--- --- ---\n";
vec.push_back(T()); // 2
std::cout << "--- --- ---\n";
現在輸出看起來更加完整:
Constructor
Move Constructor
Destructor
--- --- ---
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
--- --- ---
Destructor
Destructor
第一組:
Constructor
Move Constructor
Destructor
對應於第一個push_back
調用:
vec.push_back(T()); // 1
輸出可能很容易解密:
Constructor // Create a temporary
Move Constructor // Move a temporary into the internal vector storage
Destructor // Destroy a temporary
第二組:
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
對應於第二個push_back
調用:
vec.push_back(T()); // 2
稍微復雜一點:
Constructor // create a temporary
Move Constructor // move it into the newly allocated vector storage
Copy Constructor // copy previously created element into the new storage
Destructor // destroy old storage
Destructor // destroy temporary
在這里您應該記住, 向量類在內部分配其內存,然后對其進行管理以為所有元素提供足夠的空間。 因此,如果添加更多元素,則會發生新分配,並且會將舊元素復制或移動到新存儲中。
在已知大小的情況下,您可以使用reserve
方法,該方法只是為特定數量的元素保留足夠的內存。 它允許避免在將新元素添加到向量中(至少直到不超過保留大小)的情況下,在這些重新分配期間避免不必要的內存重新分配和復制或移動元素。
第三組:
Destructor
Destructor
對應於程序結尾處的向量 vec
析構函數調用。
emplace_back對於“僅移動”類型(例如std :: unique_ptr)很重要。
這是錯誤的,並且過於簡單。 並非所有容器均被平等地創建。 對於您的向量示例,如果我們使用reserve
則實現可以執行移動分配而不是構造,從而消除了我們的復制/外部析構函數:
std::vector<T> v;
v.reserve(2);
v.emplace_back(1);
v.emplace_back(1);
輸出:
Constructor
Constructor
---
Destructor
Destructor
對於一組:
std::set<T> s;
s.emplace(1);
s.emplace(1);
我們得到相同的輸出。 為什么呢 集合在理論上應該只構造一個對象,因為集合是唯一的對嗎? 實際上,典型的實現會構造一個臨時節點以執行比較,即使它從未進入容器也要考慮額外的構造/破壞。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.