[英]vector push_back calling copy_constructor more than once?
我對向量push_back的行為感到有些困惑,在以下代碼段中,我希望復制構造函數僅被調用兩次,但輸出表明並非如此。 是導致這種行為的向量內部重組嗎?
輸出:
Inside default Inside copy with my_int = 0 Inside copy with my_int = 0 Inside copy with my_int = 1
class Myint
{
private:
int my_int;
public:
Myint() : my_int(0)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
void set(const int &x)
{
my_int = x;
}
}
vector<Myint> myints;
Myint x;
myints.push_back(x);
x.set(1);
myints.push_back(x);
怎么了:
x
是通過push_back
插入的。 出現一個副本:用參數初始化新創建的元素。 my_int
被視為零,因為x
的默認構造函數my_int
其初始化。
第二個元素是push_back
; 由於已達到內部容量 ,因此向量需要重新分配內存。
由於沒有為Myint
1隱式定義move構造函數,因此選擇了復制構造函數。 第一個元素被復制到新分配的內存中(它的my_int
仍然為零...因此復制構造函數再次將my_int
顯示為0
),然后復制x
來初始化第二個元素(與步驟1中的第一個元素一樣)。 這次x
將my_int
設置為1,這就是復制構造函數的輸出告訴我們的。
因此,通話總數為三。 這可能因一個實現而異,因為初始容量可能不同。 但是,最少要打兩個電話。
您可以通過預先保留更多內存來減少副本數量-即更高的向量容量,因此無需重新分配:
myints.reserve(2); // Now two elements can be inserted without reallocation.
此外,在插入時,您可以刪除副本:
myints.emplace_back(0);
這“放置”了一個新元素emplace_back
是一個可變參數模板,因此可以接受任意數量的參數,然后將其轉發給元素構造函數,而無需復制或移動。
1因為有一個用戶聲明的副本構造函數。
當通過第二個push_back
增加向量的大小時,必須將向量的現有內容復制到新緩沖區中。 要進行驗證,請在第一個push_back
之后輸出myints.capacity()
,它應為1
。
這取決於為std::vector
類型的對象保留了多少內存。 似乎在第一次執行push_back
,僅為一個元素分配了內存。 當第二次調用push_back
時,將重新分配內存以為第二個元素保留內存。 在這種情況下,矢量中已經存在的元素將被復制到新位置。 然后添加第二個元素。
您可以自己保留足夠的內存,以逃避復制構造函數的第二次調用:
vector<Myint> myints;
myints.reserve( 2 );
你明白了...它正在調整大小。 但我只是指出,如果您要依靠構造函數進行bean計數,您可能會對“放置”感興趣:
#include <iostream>
#include <vector>
using namespace std;
class Myint
{
private:
int my_int;
public:
explicit Myint(int value = 0) : my_int(value)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
Myint(const Myint&& x) noexcept : my_int(x.my_int) {
cout << "Inside move with my_int = " << x.my_int << endl;
}
};
int main() {
vector<Myint> myints;
myints.reserve(2);
myints.emplace_back(0);
myints.emplace_back(1);
// your code goes here
return 0;
}
那應該給你:
Inside default
Inside default
而且,由於move構造函數上的noexcept ...如果刪除reserve
您將獲得移動,而不是副本:
Inside default
Inside default
Inside move with my_int = 0
副本上移動的這種數據類型沒有真正的優勢。 但是從語義上講,如果您的數據類型更“重”,並具有“移動”其成員的方式,這更像是將某個指針的所有權轉移到大型數據結構,則可能會有很大的不同。
您假設復制構造函數的其他調用來自向量的內部重組是正確的。
請參閱此答案以獲取更多詳細信息: https : //stackoverflow.com/a/10368636/3708904
或出於需要構造副本的原因而給出以下答案: https : //stackoverflow.com/a/11166959/3708904
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.