我想知道C ++复制/移动构造函数和赋值运算符,让我们首先给出代码示例:
标题:
class Person
{
public:
Person();
Person(const char * name, int age);
Person(const Person &person);
Person(Person&&) noexcept;
virtual ~Person();
Person &operator=(const Person & other);
Person &operator=(Person &&other) noexcept;
char *getName() const;
int getAge() const;
private:
char *name;
int age = 0;
};
资源:
Person::Person() : age(0)
{
this->name = new char[100];
memset(this->name, 0, sizeof(char)*100);
}
Person::Person(const char * name, int age) : Person()
{
std::strcpy(this->name, name);
this->age = age;
}
Person::Person(const Person &person)
{
if(this == &person)
{
return;
}
//delete[](name);
this->name = new char[100];
memset(this->name, 0, sizeof(char)*100);
std::strcpy(name, person.name);
age = person.age;
}
Person::Person(Person &&other) noexcept
{
if(this == &other)
{
return;
}
//delete[](name);
name = other.name;
age = other.age;
other.name = nullptr;
other.age = 0;
}
Person &Person::operator=(const Person &other)
{
if(this == &other)
{
return *this;
}
delete[](name);
name = new char[100];
memset(name, 0, sizeof(char)*100);
std::strcpy(name, other.name);
age = other.age;
return *this;
}
Person &Person::operator=(Person &&other) noexcept
{
if(this == &other)
{
return *this;
}
delete[](name);
name = other.name;
age = other.age;
other.name = nullptr;
other.age = 0;
return *this;
}
Person::~Person() {
delete[](name);
name = nullptr;
}
现在的问题是:如果copy
,我们是否真的需要在move
和this==&other
构造函数中检查相等性?因为它是一个构造函数,不可能与其他人相等。它还需要在copy
和move
构造函数中我们delete
(免费)的记忆吗?因为尚未分配内存,那么为什么需要删除它?我这样说是因为我在许多C ++教程中看到他们删除了内存并检查是否相等。
所以,如果我是对的,那么copy
和move
构造函数可以这样写:
Person::Person(const Person &person) : Person()
{
std::strcpy(name, person.name);
age = person.age;
}
Person::Person(Person &&other) noexcept
{
name = other.name;
age = other.age;
other.name = nullptr;
other.age = 0;
}
还有如何在move
任务中检查平等?
Person &Person::operator=(Person &&other) noexcept
谢谢!
我想知道C ++复制/移动构造函数和相等的运算符...
我认为你的意思是赋值运算符operator=
。等运算符将是operator==
。
它是否真的需要在复制和移动构造函数中检查是否相等,如果这= =&&other?
不,你不需要如你所说的那样。
是否需要在复制和移动构造函数中删除(释放)内存?
你需要在移动和复制分配中使用它,因为你必须释放旧的内存来复制(或只是设置指针)其他Person
的内存。您的构造函数不需要删除。
所以如果我是对的,那么复制和移动构造函数可以这样写
是的,这些是正确的。你确定你真的想为每个人修复100个字节吗?
还有如何检查移动分配中的相等性?
我不会在移动分配中检查是否相等,因为移动是一种非常便宜的操作,并且您不太可能要分配相同的对象。
不,构造函数中不需要自我初始化检查。主要是因为它意味着你试图用未初始化的对象初始化对象,这是一个坏主意。标准库只是将此类用途视为未定义的行为。
确保自我分配是你应该做的事情,因为它可能发生在适当的程序中。但是明确的检查是你应该避免的:它会迫使每个人为这张支票支付费用,即使这是为了很少发生的事情。即使在自我分配的情况下,最好编写赋值运算符以使其正常工作:
Person &Person::operator=(Person &&other) noexcept
{
using std::swap;
swap(name, other.name);
swap(age, other.age);
return *this;
}
它在自动分配的情况下运行良好 - 与自身交换一些数据。如果内联,它可能会完全完全优化。一般来说,原始名称的破坏推迟到other
破坏,但没有进行额外的工作,并且没有打击性能。复制分配可写为:
Person &Person::operator=(const Person &other)
{
using std::swap;
auto new_name = new char[100];
memset(new_name, 0, sizeof(char)*100);
std::strcpy(new_name, other.name);
swap(name, new_name);
age = other.age;
delete[](new_name);
return *this;
}
相同的操作,一般情况下没有性能损失,在自我分配的情况下工作,容易做出强大的异常保证,使用智能指针代替原始指针。