2016-01-18 61 views
3

我有一个简单的RAII包装管理某些资源。这里的接口:如何删除移动赋值运算符并保​​留与std容器的兼容性?

struct ResourceWrapper 
{ 
    explicit ResourceWrapper(RESOURCE resource); 
    ResourceWrapper(const ResourceWrapper& other); 
    ResourceWrapper& operator=(const ResourceWrapper& other); 
    ~ResourceWrapper(); 

    ResourceWrapper(ResourceWrapper&& other) = delete; 
    ResourceWrapper& operator=(ResourceWrapper&& other) = delete; 
}; 

的这里的问题是,我不能再尽快将此类std容器和算法,我明确地删除移动赋值运算符。显然,我确实需要删除或正确实施它,因为我刚刚学会了艰难的方式。

另一种选择是通过常规赋值操作符实现移动赋值,但我不确定如何正确执行。我想我需要像std::remove_reference这样的东西?我想知道它是否会删除太多参考文献,并导致创建不必要的临时对象。

+0

你阻止移动,但促进复制?听起来怪怪的。它是什么资源? –

+0

@DavidHaim:确实如此。无论它是什么资源都无所谓,我只想尽可能少地使用代码。我不能放弃复制,但我可以放弃移动。 –

+1

放下移动的方法是不定义它,你所做的不是“放下移动”,而是“毒素移动,因此不可能复制右值”。这不一样。 –

回答

12

很明显,我确实需要删除或正确实施它,因为我刚刚学会了艰难的方式。

不,你不知道。

你的类有一个用户定义的复制构造函数,拷贝赋值操作符和析构函数,所以编译器将定义移动赋值运算符为您服务。

因此,只要停止尝试删除它,该类将被复制而不是移动。

随着已删除移动操作,您不能复制类型的右值,即变得非常难以用作值类型(包括在容器中)。随着没有移动操作它只会做rvalues的深层副本,这是安全的,可能是你想要的。

如果您希望课程完全不可移动并且不可复制,则删除移动操作才有意义。像对象身份至关重要的互斥体类型,而不是它的价值。拥有可删除移动的可复制类型永远没有意义。

+0

我强烈怀疑它没有发生,我正在处理的错误是由默认移动分配引起的。我猜我必须正确实施移动任务才能测试该假设? –

+1

@VioletGiraffe为了测试这样一个假设(这将表明你正在使用的编译器中存在一个错误),你可以简单地按照副本实现移动:'ResourceWrapper(ResourceWrapper && other):ResourceWrapper(other){}'。注意后者确实会调用copy ctor。 – Angew

+0

@Angew:构造函数不是问题,赋值是。不是'ResourceWrapper&operator =(ResourceWrapper && other){return * this = other;}'递归吗?或者,如果我使用'return * this = std :: forward(other)',它只会是递归吗? –