Search code examples
c++c++11c++14shallow-copy

Why move semantics have the same behavior as shallow copy in dynamic mem allocation?


In the classes dealing with dynamic mem allocation, shallow copy basically causes the program to delete a resource twice. In move operations, the original pointer no longer points to the resource, So But why the same behavior occurs in move semantics? e.g:

#include <utility>
#include <cstring>
using namespace std;
class MyString
{
    char* cstr;
 public:
    MyString(const char* arg)
    : cstr(new char[strlen(arg)+1])
    {
        strcpy(cstr, arg);
    }
    MyString(MyString&&) = default;
    MyString& operator=(MyString&&) = default;
    MyString(const MyString&) = delete;
    MyString& operator=(const MyString&) = delete;
    ~MyString()
    {
        delete[] cstr;
    }
};

int main()
{
    MyString S1{"aaa"};
    MyString S2 = move(S1); // error

}

I've tried with 3 different compilers and i got the same results.


Solution

  • The implicitly generated move constructor move-constructs each member. Your member is a pointer. Moving a pointer (or any other primitive object) is same as copying it.

    So, since your move constructor does nothing else besides moves the pointer, the moved from MyString object will still be pointing to the same pointee object as the moved to MyString object. And when both are destroyed, the destructor will try to delete the pointee twice.

    You need to follow the rule of 5: If any of destructor, move/copy constructor, move/copy assignment needs to be implemented, then all of them probably need to be implemented (or deleted). You've implemented the destructor to delete an owned pointer, so you must implement the move constructor (and the others) such that the moved from (or copied from) object no longer points to the object that it no longer owns.

    Why move semantics have the same behavior as shallow copy in dynamic mem allocation?

    Because moving is just another word for shallow copying. The move constructor and assignment operator are there to be given a custom implementation in case the moved from object needs to be cleaned up to maintain the class invariant. Just like the copy constructor and copy assignment operator are there to make a deep copy that does not break the class invariant.