我问的东西看起来微不足道,但我遇到了问题。为了便于解释,我们假设这样的结构:
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){*m_Number=*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()应该返回一些有效但未确定的东西,而在这里我只是段错误。我可以在value()和setValue()中检查m_Number但你意识到它在实际代码中是一个巨大的拖累。
2)
MyClass(MyClass&& other)
:m_Number(other.m_Number)
{
other.m_Number= new int(3);
}
但是一个可以抛出的移动构造函数是不行的(或者至少我理解它)并且它也是性能增强的拖累,实际上这个代码与复制构造函数相同或更差。
你怎么看?我错过了什么吗?
有没有首选方法?
提前致谢
答案 0 :(得分:4)
首先,没有理由在这里使用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;
}
答案 1 :(得分:1)
您正在m_Number
来电中取消引用您的指针。如果.value()
无效,您将始终发生段错误。
您对移动构造函数的第一个解决方案是正确的,您应该将“其他”对象设置为默认状态。要解决此问题,您可以使 ...
sheet = ctx.workbook.worksheets.getItem("Sheet1");
sheet.getRange("C:C").insert('right');
await ctx.sync();
let range = sheet.getRange("C4:C7");
range.values = [["foo"],["bar"]];
await ctx.sync();
...
方法抛出,或者在不存在资源的情况下返回默认值。
您的析构函数已经考虑了空案例,因此请确保其余部分也考虑到它。
答案 2 :(得分:0)
如果修改MyClass
以使m_Number = nullptr
是一个有效的状态是合理的,那么你的第一种方法可能是最好的(如果它也是默认状态也是最好的做法)。我认为如果与MyClass
关联的无堆内存不是有效状态,则应该在std::unique_ptr
内分配它,并将原始指针传递给它而不是实现移动构造
如果1.
不是一个选项,这是一个合理的方法。虽然分配不需要的内存肯定会受到性能影响,但它很小,特别是考虑到你正在构建一个类作为此操作的一部分(它本身需要内存)。如果它是你的例子中需要的一小块内存,内存分配器可能会从它自己的池中获取它,而不需要系统调用。如果它是一大块内存(正如我所期望的那样,因为你正在实现移动语义),那么在大多数现代操作系统上它将是一个惰性分配(因此它仍然比复制构造函数更好)。
答案 3 :(得分:-2)
不要使用原始拥有指针,将您的类转换为使用std::unique_ptr
,所有问题都将消失。