I am a C++ newbie, and trying to figure out what the best practices are for writing the Big Five member functions, as prescribed by C++11's unofficial Rule of Five.My class with a raw pointer is:class MemoryBlock{public:    // Default constructor    explicit MemoryBlock(): _length{0}, _data{nullptr} {}    explicit MemoryBlock(const int l): _length{l}, _data{new int[l]} {}    // Big-Five    // --------    // Best Practices?:    // (Copy Constructor)->(Copy Assignment)->(Move Assignment)->(Move Constructor)->(Destructor)    // See the following for more detailed explanations    // Copy constructor    // This approach follows three steps    // (1) Initialize all non-pointer data member with the rhs data, easy!    // (2) Initialize all pointer data member with appropriate new.    // (3) Deep copy all pointers, by either looping thru, or memcopy    MemoryBlock(const MemoryBlock& rhs)        : _length{rhs._length},        _data{new int[rhs._length]}    {        // for (int i = 0; i < rhs._length; ++i)        // {        //     _data[i] = rhs._data[i];        // }        //        // Using std::copy is better?         std::copy(rhs._data, rhs._data + _length, _data);    }    // Copy assignment    MemoryBlock& operator=(const MemoryBlock& rhs)    {        // This is the 1st approach        // Compare this pointer, i.e., address same or not!!        // if (this != &rhs)        // {        //     delete [] _data;        //     _length = rhs._length;        //     _data = new int[rhs._data];        //     std::copy(rhs._data, rhs._data + _length, _data);        // }        // This is the 2nd approach, a better approach        // This approach follows three steps        // (1) Make sure this is not &rhs        // (2) Create an new instance from rhs by calling copy constructor        // (3) Swap this instance with *this        if (this != &rhs)        {            MemoryBlockVA copy = rhs;            std::swap(copy, *this);        }        return *this;    }    // Move assignment    MemoryBlock& operator=(MemoryBlock&& rhs)    {        // This 1st approach follows four steps        // (1) Make sure this is not &rhs        // (2) Reclaim original pointer data resources by delete        // (3) Shallow copy all data member, including pointers        // (4) Set rhs back to nullptr or zeros        if (this != &rhs)        {            delete [] _data;            _length = rhs._length;            _data = rhs._data;            rhs._length = 0;            rhs._data = nullptr;        }        // This 2nd approach is given by a textbook        // std::swap(_length, rhs._length);        // std::swap(_data, rhs._data);        return *this;    }    // Move constructor    MemoryBlock(MemoryBlock&& rhs)        : _length{0},        _data{nullptr}    {        // This is the 1st approach        // _length = rhs._length;        // _data = rhs._data;        // rhs._length = 0;        // rhs._data = nullptr;        // This is the 2nd approach, a better and smarter approach!        *this = std::move(rhs);     }    ~MemoryBlock()    {        // Only need to take care of the pointer data member, to reclaim them.        if (_data != nullptr)        {            delete [] _data;        }    }    int length() const    {        return _length;    }private:    int _length;    int* _data;};First, please feel free to suggest places for improvement in this code. I gathered ideas here and there, from websites and textbooks, and then took notes myself.But my specific questions are:Are there any potential problems with this approach? I mean following the order of Copy Constructor → Copy Assignment → Move Assignment → Move Constructor → Destructor. I'm thinking that Copy Assignment can be easily and safely written using the copy and swap idiom based on the existing Copy Constructor, and Move Constructor can be easily and safely written based on Move Assignment.In writing assignment operators, should we always check and see if if (this != &rhs)?In writing the Move Assignment, is the 2nd approach for doing swaps better than the 1st one?By better, I mean that it has the same effect without sacrificing safety.Here is a small working example using this class:#include MemoryBlock.hppint main (int argc, const char* argv []){    MemoryBlock x(10000);    std::cout<< x's length =  << x.length() << std::endl;    return 0;}
Writing order and move assignment when following the Rule of Five
c++;c++11;memory management