据我所知,void构造函数的目的是将所有元素从选择状态重置到正确的新生状态。
所以。
#include <cstring>
class STR_imp
{
char* cstr;
static size_t getSize(const char* incstr)
{
return std::strlen(incstr)+1;
};
STR_imp& fillBy(const char* incstr)
{
for(int i=0,size=getSize(incstr);i<size;i++)
this->cstr[i]=incstr[i];
return *this;
};
STR_imp& reset()
{
this->cstr=nullptr;
return *this;
};
STR_imp& invoke()
{
if(this->cstr!=nullptr)
delete[] this->cstr;
return *this;
};
public:
STR_imp():cstr(nullptr)
{};
~STR_imp()
{this->invoke().reset();};
STR_imp(const char* const& incstr);//splited for reading
STR_imp(char*&& incstr):cstr(incstr)
{
incstr=nullptr;
};
STR_imp(const STR_imp& instr);//splited for reading
STR_imp(STR_imp&& instr):cstr(instr.cstr)
{
instr.reset();
};
STR_imp& operator= (const char* const& incstr);//splited for reading
STR_imp& operator= (char*&& incstr)
{
this->invoke();
this->cstr=incstr;
incstr=nullptr;
return *this;
};
STR_imp& operator= (const STR_imp& instr);//splited for reading
STR_imp& operator= (STR_imp&& instr)
{
this->invoke();
this->cstr=instr.cstr;
instr.reset();
return *this;
};
char* operator() ()
{
return this->cstr;
};
};
STR_imp::STR_imp(const char* const& incstr):cstr(new char[getSize(incstr)])
{
this->fillBy(incstr);
};
STR_imp::STR_imp(const STR_imp& instr):cstr(new char[getSize(instr.cstr)])
{
this->fillBy(instr.cstr);
};
STR_imp& STR_imp::operator= (const char* const& incstr)
{
this->invoke();
this->cstr=new char[getSize(incstr)];
this->fillBy(incstr);
return *this;
};
STR_imp& STR_imp::operator= (const STR_imp& instr)
{
this->invoke();
this->cstr=new char[getSize(instr.cstr)];
this->fillBy(instr.cstr);
return *this;
};
我在这里只想解决关于move语义的问题,因为你应该一次只问一个问题。
移动构造函数一般可以让对象处于任何它想要的状态,只要你把后置条件记录下来,让类的用户知道会发生什么。
例如,在C++标准库中的许多类都声明一个move-from对象处于一个 未详,但有效 状态。 这意味着你不能对对象的状态做任何假设,但你可以做到 问事 或者你可以手动将其重置为清除状态。("正确 "的说法是,你只能调用对象的没有前提条件的方法)。
我相信之所以选择这条路线,是因为实现移动语义的最有效方法是简单地交换目标对象和源对象的值。 通常这是很好的,因为在很多情况下,源对象要么会被立即销毁,要么会被手动清除。
你通常的做法是。
实现一个有效的 swap()
方法。
void STR_imp::swap(STR_imp & other) {
std::swap(cstr, other.cstr);
}
在移动分配时,只需交换。
STR_imp& STR_imp::operator=(STR_imp&& instr) {
swap(instr);
return *this;
}
在移动构建时,先构建默认状态,然后交换。
STR_imp::STR_imp(STR_imp&& instr) : STR_imp{} {
swap(instr);
}
这种模式有多个优点 最大的优点是,它的 真的 难于上青天 swap()
方法正确工作。另一个优点是,它迫使你支持交换,这在很多不同的场景下,它本身就很有用。
在C++中,一个destructor就像它的名字一样,摧毁了你的对象,这意味着在调用它之后,你的对象的底层内存已经被释放了,这也意味着你不能再访问它,因为它在你的应用程序中不存在。这也意味着你不能再访问它,因为它不在你的应用程序中。
如果你想重置一个对象,你可以直接调用你的 reset
函数,它将按照你想要的方式清除数据。如果你想要一个干净的对象副本,你可以使用移动赋值操作符,然后调用 reset
复制的对象上。
请注意,在复制对象上设置 cstr
到 nullptr
并不能释放内存。以下是你应该做的。
~STR_imp() { delete cstr; }
STR_imp& reset()
{
delete cstr;
cstr = nullptr;
return *this;
}