简体   繁体   中英

C++ copy/move constructor and the assignment operator

I want to know about C++ copy/move constructor and assignment operator, let's first give code example:

Header:

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

Source:

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

Now the question is: Does it really need in the copy and move constructors that we check for equality if this==&other ? Because it is a constructor and it is impossible to be equal with other. And also Does it need that in the copy and move constructors we delete (free) the memory? Because the memory has not been allocated yet, then why it needs to be deleted? I say this because I saw in many C++ tutorials that they deleted the memory and check for equality.

So if I am right, then the copy and move constructor can be written like this:

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

And also how about checking for equality in move assignment?

Person &Person::operator=(Person &&other) noexcept

Thanks!

I want to know about C++ copy/move constructor and equal operator...

I think you meant the assignment operator operator= . The equal operator would be operator== .

Does it really need in the copy and move constructors that we check for equality if this==&other?

No, you don't need this as you already stated.

Does it need that in the copy and move constructors we delete (free) the memory?

You'll need it in your move- and copy-assignment, because you have to release the old memory to copy (or just set the pointer to) the memory of the other Person . Your constructor won't need a delete.

So if I am right, then the copy and move constructor can be written like this

Yes, these are correct. Are you sure you really want to have fixed 100 bytes for every person?

And also how about checking for equality in move assignment?

I would not check for equality in move assignment, because move is a very inexpensive operation and it is very unlikely that you are going to assign the same object.

No, self-initialization check is not needed in constructor. Mainly because it means you are trying to initialize object with uninitialized object, which is a bad idea. Standard library just treats such use as undefined behavior.

Making sure that self-assignment works is something you should do, as it can happen in proper programs. But explicit check is something you should avoid: it forces everyone pay cost for that check, even if it is for something rarely happening. It is better to write your assignment operators to work properly even in case of self-assignment:

Person &Person::operator=(Person &&other) noexcept
{
    using std::swap;
    swap(name, other.name);
    swap(age, other.age);
    return *this;
}

It works well in case of self-move assignment — swaps some data with itself. If inlined, it will be likely completely optimised away entirely. In general, destruction of original name is deferred until other destruction, but no extra work is done, and there is no perfomance hit. Copy assignment can be written as:

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

Same operations, no perfomance hit in general case, works in case of self-assignment, easy to make strong exception guarantee, if smart pointers are used instead of raw pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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