簡體   English   中英

什么是這個奇怪的復制構造錯誤抱怨?

[英]What is this strange copy constructor error complaining about?

我在Visual Studio 2017上。最近,因為我不喜歡C ++的不符合標准,所以我繼續並禁用了選項中的非標准語言擴展。 到現在為止還挺好。 現在我有一個問題。

#include <iostream>
#include <vector>


struct Vertex
{
    Vertex(float pos) { }
    Vertex(Vertex& other) { }
};

std::vector<Vertex> arrayOfVertices;

int main()
{
    arrayOfVertices.emplace_back(7.f);
}

這不會在Visual Studio中編譯,它給出的唯一錯誤是:

“編譯器中發生內部錯誤”

如果我啟用語言擴展,它編譯得很好。 如果我禁用語言擴展並使復制構造函數采用const Vertex&並且它編譯得很好。

所以我在一些在線編譯器上嘗試了GCC,如果復制構造函數沒有采用const引用參數,它將無法編譯,從而產生各種錯誤。 似乎最有意義的是:

錯誤:從'Vertex'類型的右值開始無效初始化'Vertex&'類型的非const引用

我認為復制構造函數不必是const,在我的情況下我想修改另一個引用中的東西。 我知道非const參數不能接受r值引用,但我測試了它,結果發現在vector::emplace_back()中根本沒有調用復制構造函數:

#include <iostream>
#include <vector>

struct Vertex
{
    Vertex(float pos) 
    { 
        std::cout << "Calling constructor\n";
    }
    Vertex(const Vertex& other) 
    { 
        std::cout << "Calling copy constructor\n";
    }
};

std::vector<Vertex> arrayOfVertices;

int main()
{
    arrayOfVertices.emplace_back(7.f); // Normal constructor called if const,
                                       // doesn't compile if non-const

    auto buff = malloc(sizeof(Vertex)); // Placement new
    new (buff) Vertex(7.f); // Normal constructor called whether const 
                            // or non-const. This is what I thought emplace_back did

}

所以我不知道發生了什么。 我想首先知道為什么如果沒有調用復制構造函數會發生這種情況,並且如果在這種情況下有一種方法可以在我的復制構造函數中使用非const,也就是使用vector::emplace_back() ,因為似乎只有使用vector::emplace_back()才會出現這個問題。

問題是你沒有移動構造函數。

當你向emplace_back std::vector請求emplace_back ,它必須確保它有足夠的存儲空間來構造新對象。 這個例程的一部分是實例化一堆代碼, 元素從舊緩沖區移動到任何新分配的緩沖區(如果需要)。 即使在運行時沒有重新分配,該代碼也將由模板實例化。

您的類具有用戶定義的復制構造函數,因此隱式刪除了移動構造函數。 因此,將原始緩沖區中的任何元素移動到新緩沖區中的嘗試將轉變為通過重載解析來復制的嘗試。 您對新位置的關注實際上是一個紅色的鯡魚,真正的問題在這個簡單的例子中很明顯:

Vertex v1{7.f},
       v2{std::move(v1)};
       // Error, the xvalue from `move` can't bind to a non-const reference

您可以通過將移動構造函數返回來輕松地使錯誤變得沉默,例如,通過顯式默認它:

struct Vertex
{
    Vertex(float) 
    { 
        std::cout << "Calling constructor\n";
    }

    Vertex(Vertex&&) = default;

    Vertex(Vertex&) 
    { 
        std::cout << "Calling copy constructor\n";
    }
};

永遠不要忘記,在C ++ 11中,0/3的規則成為0/3/5的規則。 仔細考慮為您的類移動語義。

顯然,如果編譯器發出內部錯誤,那就是編譯器錯誤。

emplace_back(7.f)使用構造函數Vertex(float pos)來放置對象 - 復制構造函數不直接涉及。

錯誤的實際原因是不同的。 當您在向量中放置時,通常可能會發生重新分配。 如果是,則必須將向量中的所有對象重新定位到內存中的新位置。

顯然,關於是否發生重新分配,它是一個運行時條件。 在運行時出現編譯錯誤是不可行的; 因此,如果對象不支持重新分配,則必須在編譯時使用emplace_back時發生錯誤; 即使該調用的向量恰好是空的。

標准術語可在C ++ 14表87中找到:為了進入向量,元素類型必須是MoveInsertable和MoveAssignable。

在不太詳細的情況下,非const復制構造函數和沒有move-constructor的組合意味着該對象未能通過MoveInsertable要求,因為所述要求中的rvalue參數不會綁定到非const左值引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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