Принудительное назначение копии над оператором назначения перемещения - PullRequest
3 голосов
/ 30 января 2020

Предположим, у меня есть объект с заданными операторами назначения копирования и перемещения. Когда я пишу это:

Object a(/*parameters 1*/);
/* some code */
a = Object(/*parameters 2*/);

третья строка, скорее всего, вызовет оператор присваивания перемещения. Как я могу заставить компилятор использовать вместо этого назначение копирования? Кроме того, как я могу принудительно копировать конструкторы перемещения? В основном я прошу об обратном std :: move ()

Зачем мне это нужно?

Код между строками 1 и 3 (который я не могу изменить) получает некоторые указатели на поля a, то есть важно, чтобы структура памяти a не изменялась (что, скорее всего, делает перемещение), а перезаписывалась новыми значениями.

Кроме того, мой объект - это просто std::vector. Когда я перемещаю его, компилятор просто перенаправляет указатель своего базового массива в массив вектора rvalue. Когда я копирую назначить его (а предыдущий вектор a был длиннее), тогда его базовый массив будет перезаписан, но их адреса останутся прежними. К сожалению, «некоторый код» хранит указатели типа &a[2], и они могут не изменяться.

Ответы [ 3 ]

2 голосов
/ 30 января 2020

Мой объект - просто std::vector. Когда я перемещаю его, компилятор просто перенаправляет указатель своего базового массива в массив вектора rvalue. Когда я копирую назначить его (а предыдущий вектор был длиннее), тогда его базовый массив будет перезаписан, но их адреса останутся прежними. К сожалению, в «некотором коде» хранятся указатели типа &a[2], и они могут не изменяться.

Тогда вам потребуется нечто иное, чем назначение копирования, поскольку назначение копирования также небезопасно.

Конечно, этот пример работает:

auto a = std::vector{1, 2};
auto const b = std::vector{3, 4};

auto pointer = a.data() + 1; // points to second element

a = b; // copy

std::cout << *pointer; // prints 4?

Это может работать, но не всегда!

Учтите это:

auto a = std::vector{1, 2};
auto const b = std::vector{3, 4, 5}; // three elements!

auto pointer = a.data() + 1; // points to second element

a = b; // copy. a's buffer is too small, must reallocate

std::cout << *pointer; // points in the old buffer, invalid.

Указатель на элементы вектора, который затем назначается, является небезопасным !


Что вы можете сделать тогда?

Определите свою собственную операцию:

struct Object {
    // ... stuff

    auto safe_assign(Object const& other) & -> void {
        mem1 = other.mem1;
        mem2 = other.mem2;

        // let 'mem_vec' be your memeber vector
        assert(mem_vec.size() == other.mem_vec.size());

        // safe copy, will never reallocate.
        std::copy(other.mem_vec.begin(), other.mem_vec.end(), mem_vec.begin());
    }
};
1 голос
/ 30 января 2020

Точно так же, как std::move берет объект и возвращает ссылку на него по значению, вы можете создать copy, который берет объект и возвращает ссылку на него по значению. Это будет выглядеть как

template< class T >
constexpr std::remove_reference_t<T>& copy( T&& t ) noexcept
{
    return t;
}

, и вы будете использовать его как

a = copy(Object(/*parameters 2*/));
0 голосов
/ 30 января 2020

Передача lvalue оператору присваивания

Один из способов - передать lvalue вместо rvalue оператору присваивания объект, который вы назначаете:

Object a(/*parameters 1*/);
Object b(/*parameters 2*/);
// ...
a = b; // <-- b is an lvalue, copy not move

Таким образом, будет выбран a оператор назначения копирования .


Квалификация не- объект для перемещения как const

Другой подход заключается в const -квалификации объекта, который вы не хотите перемещать. Это работает, даже если у вас есть назначение, где std::move() уже используется, потому что const -квалифицированные объекты не привязываются к rvalue ссылкам . Следовательно, оператор назначения перемещения не будет выбран. То есть:

const Object b(/*parameters 2*/);
// ...
a = std::move(b); // <-- still copies, b is const

Даже если b выше явно помечено для перемещения с помощью std::move(b), a выбран оператор назначения копирования.

...