lundi 28 novembre 2016

use std::unique_ptr to easily implment "move" semantics?

Should std::unique_ptr<> be used as an easier way to implement move semantics?

For a class like

class Foo
{
    int* m_pInts;
    // other members ...

public:
    Foo(size_t num) {
        m_pInts = new int[num];
    }
    ~Foo() {
        delete[] m_pInts;
    }

    // no copy, but move
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;
    Foo(Foo&& other) {
        *this = std::move(other);
    }
    Foo& operator=(Foo&& other) {
        m_pInts = other.m_pInts;
        other.m_pInts = nullptr;
        return *this;
    }
};

Implementing move becomes more difficult as data members are added. However, the moveable data can be placed in a separate struct, an instance of which is managed by std::unique_ptr<>. This allows =default to be used for move:

class Bar
{
    struct Data
    {
        int* m_pInts;
        // other members ...
    };
    std::unique_ptr<Data> m_pData = std::make_unique<Data>();

public:
    Bar(size_t num) {
        m_pData->m_pInts = new int[num];
    }
    ~Bar() {
        if (m_pData) // might have been std::move()d to another instance
            delete[] m_pData->m_pInts;
    }

    // no copy, but move
    Bar(const Bar&) = delete;
    Bar& operator=(const Bar&) = delete;
    Bar(Bar&& other) = default;
    Bar& operator=(Bar&& other) = default;
};

Other than the memory for the unique_ptr<> instance always being on the heap, what other problems exist with an implementation like this?

Aucun commentaire:

Enregistrer un commentaire