我在问一些看起来很琐碎但我有问题的事情。为了解释一下,让我们假设一个像这样的结构:
class MyClass{
int* m_Number;
public:
int value() const {return *m_Number;}
void setValue(int val){*m_Number=val;}
MyClass() : m_Number(new int(3)){}
~MyClass() {if(m_Number) delete m_Number;}
MyClass(const MyClass& other):m_Number(new int(*other.m_Number)){}
MyClass& operator=(const MyClass& other){if(m_Number) *m_Number=*other.m_Number; else m_Number=new int(*other.m_Number); return *this;}
MyClass& operator=(MyClass&& other){std::swap(m_Number,other.m_Number); return *this;}
MyClass(MyClass&& other){
//????
}
}我应该放什么进去?我的选择是:
1)
MyClass(MyClass&& other)
:m_Number(other.m_Number)
{
other.m_Number=nullptr;
}但是,移出对象不处于有效状态。调用value()应该返回一些有效但未定的内容,而这里我只是分段错误。我可以检查m_Number的值()和setValue(),但您意识到这在实际代码中是一个很大的阻力。
2)
MyClass(MyClass&& other)
:m_Number(other.m_Number)
{
other.m_Number= new int(3);
}但是,可以抛出的move构造函数是no go (或者至少据我理解),它也是性能增强的阻力,实际上,这段代码与复制构造函数相同或更糟。
你认为如何?
我错过了什么吗?
有更好的方法吗?
提前感谢
编辑:这个问题得到了性病委员会召集人的答复,从根本上说它与这个帖子的答案不一致。您可以在本文https://herbsutter.com/2020/02/17/move-simply/中找到它。
发布于 2017-05-09 18:47:42
首先,这里没有理由使用new和delete,您应该使用make_unique<int>来创建对象,使用unique_ptr<int>来自动管理对象。但这并不能解决您的问题,移动构造器可以做什么。除了您建议的两个选项之外,还有其他一些选择:
3)不要给它移动构造函数,只需将其作为可复制的
4)文档说明不允许对移动对象调用value或setValue,并将移动对象保留为空指针。根据您的程序中发生的移动位置,这可能会很好。如果移动-从对象从来没有访问,一切只是工作。
( 4a)如上文所述,但如果发生这种情况,则应加上健全检查:
int value() const {
assert(m_Number != nullptr);
return *m_Number;
}或者:
int value() const {
if (m_Number == nullptr)
throw std::logic_error("accessed a moved-from object");
return *m_Number;
}5)向setValue添加检查,以便在当前为空的情况下用新的int重新初始化对象,并使value返回一些默认值:
int value() const { return m_Number ? *m_Number : 0; }
void setValue(int val) {
if (!m_Number)
m_Number = new int(val);
else
*m_Number = val;
}发布于 2017-05-09 18:51:38
在.value()调用中取消引用指针。在m_Number无效的情况下,您将始终分割错误。
移动构造函数的第一个解决方案是正确的,您应该将“other”对象设置为默认状态。要解决这个问题,您可以抛出.value()方法,或者在不存在资源的情况下返回默认值。
您的析构函数已经说明了null大小写,所以请确保其馀部分也说明了这一点。
发布于 2017-05-09 19:02:31
MyClass使m_Number = nullptr是一个有效的状态是合理的(如果它也是默认状态的话),那么第一种方法可能是最好的方法。如果没有与MyClass关联的堆内存不是一个有效的状态,那么您应该在std::unique_ptr中分配它,并传递一个指向它的原始指针,而不是实现一个移动构造函数。1.不是一个选项,这是一个合理的方法。虽然分配不需要的内存的性能肯定会受到影响,但这很小,特别是考虑到您正在构建一个类作为此操作的一部分(它本身需要内存)。如果像您的例子一样需要一小块内存,内存分配器可能会从自己的池中提取它,而不需要系统调用。如果它是一大块内存(正如我所期望的,因为您正在实现移动语义),那么在大多数现代操作系统上,它将是一个延迟分配(因此它仍然比复制构造函数更好)。https://stackoverflow.com/questions/43877502
复制相似问题