samedi 10 juillet 2021

What kind of reference should use move() member function in C++ with move semantic?

Before C++11 move() method was implemented to avoid copying. In C++11 move semantic was introduced but sometimes it is easier to have move() method and call its from move-constructor and moving operator=. The move() method can take object by normal reference (l-reference) or r-reference.

What reference should we used? What option is better/cleaner/faster/...?

Here is sample code with two possibilities (C++20 required):

#include <iostream>
#include <ranges> // copy, size
#include <memory> // unique_ptr
using namespace std;

constexpr bool MOVE_WITH_LREF_IS_BETTER = true;

class Array
{
    size_t size_ = 0;
    unique_ptr<int[]> data_;

public:
    template<size_t N>
    Array(const int (&src)[N]) : size_(N), data_(make_unique<int[]>(N))
    {
        std::ranges::copy(src, data_.get());
    }

    Array(Array&& src)
    {
        if constexpr(MOVE_WITH_LREF_IS_BETTER)
            move_lref(src);
        else
            move_rref(std::move(src));
    }

    Array& operator=(Array&& src)
    {
        if constexpr(MOVE_WITH_LREF_IS_BETTER)
            move_lref(src);
        else
            move_rref(std::move(src));
        return *this;
    }

    void move_lref(Array& src)
    {
        if (&src != this)
        {
            size_ = exchange(src.size_, 0);
            data_ = std::move(src.data_);
        }
    }
    void move_rref(Array&& src)
    {
        if (&src != this)
        {
            size_ = exchange(src.size_, 0);
            data_ = std::move(src.data_);
        }
    }
    auto operator[](size_t index) const
    {
        if (index >= size_)
        {
            throw out_of_range("");
        }
        return data_[index];
    }
};

int main()
{
    constexpr int srcArray[] = { 1, 9, 9, 0 };

    Array a(srcArray);
    Array b = std::move(a);

    for (size_t i=0; i < ranges::size(srcArray); ++i)
        cout << b[i] << "\n";
}

Aucun commentaire:

Enregistrer un commentaire