![](/img/trans.png)
[英]C++ Rule of 5 copy and move (constructor and assignment) caveat: to copy or move
[英]What is copy/move constructor choosing rule in C++? When does move-to-copy fallback happen?
第一個例子:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const A&) = delete;
A(A&&) = default;
A(const int i) : ref(new int(i)) { }
~A() = default;
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
它完美地運作。 所以這里使用了MOVE構造函數。
讓我們刪除移動構造函數並添加一個副本:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const A&a)
: ref( a.ref.get() ? new int(*a.ref) : nullptr )
{ }
A(A&&) = delete;
A(const int i) : ref(new int(i)) { }
~A() = default;
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
現在編譯出現錯誤“ 使用已刪除的函數'A :: A(A &&)' ”
所以MOVE構造函數是必需的,並且沒有回退到COPY構造函數。
現在讓我們刪除copy-move和move-constructors:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const int i) : ref(new int(i)) { }
~A() = default;
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
它與“ 使用已刪除的函數'A :: A(const A&)' ”編譯錯誤有關。 現在它需要一個COPY構造函數!
所以從移動構造函數到復制構造函數有一個回退(?)。
為什么? 有沒有人知道它是如何符合C ++標准的,以及在復制/移動構造函數中選擇的實際規則是什么?
在檢查是否delete
之前,選擇它將要使用的功能。 在復制構造函數可用且移動構造函數為delete
d的情況下,移動構造函數仍然是兩者中的最佳選擇。 然后它看到它是delete
d並給你一個錯誤。
如果您有相同的示例但實際上刪除了移動構造函數,而不是將其delete
d,您將看到它編譯正常並且回退使用復制構造函數:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
A(const A&a)
: ref( a.ref.get() ? new int(*a.ref) : nullptr )
{ }
A(const int i) : ref(new int(i)) { }
~A() = default;
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
這個類根本沒有為它聲明的移動構造函數(甚至沒有隱式),因此無法選擇它。
沒有“后備”。 它被稱為重載分辨率 。 如果在重載決策中有多個可能的候選者,則根據一組復雜的規則選擇最佳匹配,您可以通過閱讀C ++標准或其草稿來找到這些規則。
這是一個沒有構造函數的例子。
class X { };
void func(X &&) { cout << "move\n"; } // 1
void func(X const &) { cout << "copy\n"; } // 2
int main()
{
func( X{} );
}
在重載決策中,綁定rvalue到rvalue的優先級高於左值的rvalue。
這是一個非常相似的例子:
void func(int) { cout << "int\n"; } // 1
void func(long) { cout << "long\n"; } // 2
int main()
{
func(1);
}
在重載分辨率中,完全匹配優先於轉換。
在這個主題的三個例子中,我們有:
1:兩個候選功能; rvalue更喜歡rvalue(如我的第一個例子)
A(const A&);
A(A&&); // chosen
2:兩個候選功能; rvalue更喜歡rvalue(如我的第一個例子)
A(const A&);
A(A&&); // chosen
3:一個候選功能; 沒有比賽
A(const A&); // implicitly declared, chosen
如前所述 ,在案例3中沒有隱含的A(A &&)聲明,因為你有一個析構函數。
對於重載解析,函數體是否存在無關緊要,它是否聲明了函數(顯式或隱式)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.