為什麼這段代碼在vs2017裡面emplace_back要求複製構造函數?
// 頭文件省略
class Foo
{
public:
Foo() = default;
Foo(const Foo) = delete;
};int main()
{
vector&svec;
svec.emplace_back();return 0;
}
錯誤 C2280 「Foo::Foo(const Foo )」: 嘗試引用已刪除的函數 test c:program files (x86)microsoft visual studio2017enterprisevc oolsmsvc14.10.25017includexmemory0 840
按道理 emplace_back 應該不要求複製構造函數吧?
而在其他編譯器比如 gcc 和 clang 在 -std=c++11 上面都正常通過?
看來代碼改了。我來指出真正的原因。因為複製構造函數要自動生成的話,前提是你沒有自己寫一個。你現在=delete了,你也屬於自己寫,所以那個Foo(Foo)就沒有自動生成了。你得自己寫一個Foo(Foo),代碼就能通過編譯了。
之所以clang++沒報錯,我猜是因為你的emplace_back沒有參數,所以直接用了默認構造函數。VC++的實現是無論如何都會去move一次的。如果你強行在clang裡面move一個Foo,你會發現你也編譯不了。
emplace_back不要求copy constructable,但是vector自己要求。當預留的空間不夠時,vector會擴展空間並且copy之前的數據,所以需要copy constructor。因為你自己delete了那個copy constructor,所以就編譯不通過了。
C++11中vector也可以利用move constructor。本來編譯器會自動生成move constructor,但是因為你主動聲明(聲明delete)了copy constructor,根據c++11的規則,編譯器不會再自動生成move。解決辦法之一是加上一句Foo(Foo) = defau< 來顯式告訴編譯器自動生成move,這樣vector就會自動用move而不是copy了。
但是注意如果你自己定義這個move constructor,則它必須是noexcept的時候vector才會用它代替copy。
推薦新用C++11的看看Effective Modern C++。
參考代碼:
#include &
#include &
#include &
class MyClass
{
public:
typedef enum
{
e1 = 1,
e2 = 2,
e3 = 3,
} Type;
private:
Type _type;
public:
MyClass(Type type): _type(type) { std::cout &<&< "create " &<&< type &<&< "
"; };
MyClass(const MyClass other) { std::cout &<&< "copy " &<&< other._type &<&< "
"; };
//MyClass(MyClass other) { std::cout &<&< "move " &<&< other._type &<&< "
"; }; // Option 1: not OK, will call copy instead
MyClass(MyClass other) noexcept { std::cout &<&< "move " &<&< other._type &<&< "
"; }; // Option 2: OK
//MyClass(MyClass other) = defau< // Option 3: OK
};
int main() {
std::vector&
list.reserve(2);
list.emplace_back(MyClass::e1);
list.emplace_back(MyClass::e2);
list.emplace_back(MyClass::e3);
}
看來輪子哥已經指出了真正的原因。那我就...來指出真正的原因背後的原因。
因為標準(n4659)規定了:
6 If the class de?nition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class de?nition declares a move constructor or move assignment operator, the implicitly declared copy constructor is de?ned as deleted; otherwise, it is de?ned as defaulted (11.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
8 If the de?nition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if
—(8.1) X does not have a user-declared copy constructor,
—(8.2) X does not have a user-declared copy assignment operator,
—(8.3) X does not have a user-declared move assignment operator, and
—(8.4) X does not have a user-declared destructor.
推薦閱讀:
※camtasia studio錄完的文件為什麼導不進pr?
※C++斷點問題求解?
※想在ASP.net中整合Bootstrap的LESS源碼,該怎麼做?
※開機總是有一個彈窗 http://www.msftconnecttest.com/redirect ?
TAG:C | MicrosoftVisualStudio | GCC | Clang |