簡體   English   中英

向量push_back多次調用copy_constructor嗎?

[英]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);

怎么了:

  1. x是通過push_back插入的。 出現一個副本:用參數初始化新創建的元素。 my_int被視為零,因為x的默認構造函數my_int其初始化。

  2. 第二個元素是push_back ; 由於已達到內部容量 ,因此向量需要重新分配內存。
    由於沒有為Myint 1隱式定義move構造函數,因此選擇了復制構造函數。 第一個元素被復制到新分配的內存中(它的my_int仍然為零...因此復制構造函數再次將my_int顯示為0 ),然后復制x來初始化第二個元素(與步驟1中的第一個元素一樣)。 這次xmy_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM