繁体   English   中英

C ++复制/移动构造函数和赋值运算符

[英]C++ copy/move constructor and the assignment operator

我想了解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;
}

现在的问题是:如果this==&other是否真的需要我们检查是否相等的copymove构造函数? 因为它是一个构造函数,所以不可能与其他函数相等。 而且是否需要在copymove构造函数中delete (释放)内存? 因为尚未分配内存,那么为什么需要删除它? 我之所以这样说,是因为我在许多C ++教程中看到他们删除了内存并检查是否相等。

所以如果我是对的,那么copymove构造函数可以这样写:

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==

如果this ==&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;
}

如果使用智能指针而不是原始指针,则相同的操作在一般情况下不会影响性能,在自分配的情况下起作用,易于做出强有力的异常保证。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM