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

时间:2018-01-04 07:15:04

标签: c++

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

现在的问题是: copymove构造函数中是否真的需要检查this==&other的相等性?因为它是一个构造函数,不可能与其他人相等。在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

谢谢!

2 个答案:

答案 0 :(得分:3)

  

我想了解C ++复制/移动构造函数和相等的运算符......

我认为你的意思是赋值运算符operator=。等于运算符为operator==

  

如果这是==& other,它是否真的需要复制并移动我们检查相等的构造函数?

不,你不需要如你所说的那样。

  

是否需要在复制和移动构造函数中删除(释放)内存?

您需要在移动和复制分配中使用它,因为您必须释放旧内存以复制(或仅设置指针)另一个Person的内存。您的构造函数不需要删除。

  

所以,如果我是对的,那么复制和移动构造函数可以像这样编写

是的,这些都是正确的。你确定你真的想为每个人修复100个字节吗?

  

还有如何检查移动分配中的相等性?

我不会检查移动分配中的相等性,因为移动是一种非常便宜的操作,并且您不太可能要分配相同的对象。

答案 1 :(得分:1)

不,构造函数中不需要自我初始化检查。主要是因为它意味着你试图用未初始化的对象初始化对象,这是一个坏主意。标准库只是将这种用法视为未定义的行为。

确保自我分配是你应该做的事情,因为它可能发生在适当的程序中。但是明确的检查是你应该避免的:它会迫使每个人为这张支票支付费用,即使这是为了很少发生的事情。最好编写赋值运算符,即使在自我赋值的情况下也能正常工作:

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;
}

相同的操作,在一般情况下没有性能,在自我分配的情况下工作,容易做出强大的异常保证,如果使用智能指针而不是原始指针。