[英]reusing the copy-and-swap idiom
我正在嘗試將復制和交換習語放入可重用的混合中:
template<typename Derived>
struct copy_and_swap
{
Derived& operator=(Derived copy)
{
Derived* derived = static_cast<Derived*>(this);
derived->swap(copy);
return *derived;
}
};
我打算通過 CRTP 將其混合:
struct Foo : copy_and_swap<Foo>
{
Foo()
{
std::cout << "default\n";
}
Foo(const Foo& other)
{
std::cout << "copy\n";
}
void swap(Foo& other)
{
std::cout << "swap\n";
}
};
但是,一個簡單的測試表明它不起作用:
Foo x;
Foo y;
x = y;
這只會打印兩次“default”,既不打印“copy”也不打印“swap”。 我在這里想念什么?
這個:
Derived& operator=(Derived copy)
沒有為基礎 class 聲明復制賦值運算符(它的簽名錯誤)。 所以Foo
中默認生成的賦值運算符不會使用這個運算符。
記住 12.8:
用戶聲明的復制賦值運算符 X::operator= 是 class X 的非靜態非模板成員 function,其中只有一個類型為 X、X&、const X&、volatile X& 或 const volatile X& 的參數。)重載賦值運算符必須聲明為只有一個參數; 見 13.5.3。 ] [注意:可以為 class 聲明一種以上形式的復制賦值運算符。 ] [注意:如果 class X 僅具有帶有 X& 類型參數的復制賦值運算符,則無法將 const X 類型的表達式分配給 X 類型的 object。
編輯不要這樣做(你能明白為什么嗎?):
你可以做:
template<typename Derived> struct copy_and_swap { void operator=(const copy_and_swap& copy) { Derived copy(static_cast<const Derived&>(copy)); copy.swap(static_cast<Derived&>(*this)); } };
但是你失去了潛在的復制省略優化。
實際上,這將分配兩次派生類的成員:一次通過copy_and_swap<Derived>
賦值運算符,一次通過派生類生成的賦值運算符。 要糾正這種情況,您必須這樣做(並且不要忘記這樣做):
struct Foo : copy_and_swap<Foo>
{
Foo& operator=(const Foo& x)
{
static_cast<copy_and_swap<Foo>&>(*this) = x;
return *this;
}
private:
// Some stateful members here
}
故事的寓意:不要為復制和交換習語寫 CRTP class 。
如果 memory 正確服務,則不能將賦值運算符作為特殊情況繼承。 我相信他們可以在需要時明確using
'd in。
此外,請注意過度使用復制和交換。 它會產生不理想的結果,其中原始文件具有可重復用於制作副本的資源,例如容器。 安全得到保證,但最佳性能卻沒有。
編譯器會自動為 Foo 生成一個復制賦值運算符,因為沒有。 如果你添加一個
using copy_and_swap<Foo>::operator=;
到 Foo 你會看到一個錯誤告訴你關於 g++ 的歧義。
也許你可以重寫它,使它看起來像這樣:
template<class Derived>
struct CopySwap
{
Dervied &operator=(Derived const &other)
{
return AssignImpl(other);
}
Derived &operator=(Dervied &&other)
{
return AssignImpl(std::move(other));
}
private:
Derived &AssignImpl(Derived other)
{
auto self(static_cast<Derived*>(this));
self->swap(other);
return *self;
}
};
它可能會全部內聯,並且可能不會比原始代碼慢。
恐怕這是一個需要宏的領域,因為關於自動生成的復制和賦值運算符的復雜規則。
無論您做什么,您都處於以下兩種情況之一:
因此,下一個問題是:自動化這樣的寫作值得嗎?
Copy-And-Swap 僅用於非常特定的類。 我不認為這是值得的。
這並不能真正回答問題( @Alexandre C. 已經回答了),但是如果你反轉 inheritance,你可以讓它工作:
template<typename Base>
struct copy_and_swap : Base
{
copy_and_swap& operator=(copy_and_swap copy)
{
swap(copy);
return *this;
}
};
struct Foo_
{
Foo_()
{
std::cout << "default\n";
}
Foo_(const Foo_& other)
{
std::cout << "copy\n";
}
void swap(Foo_& other)
{
std::cout << "swap\n";
}
};
typedef copy_and_swap<Foo_> Foo;
int main()
{
Foo x;
Foo y;
x = y;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.