std :: launder, std :: vector и move только для конструктивных типов - PullRequest
0 голосов
/ 31 декабря 2018

Для запроса объекта из моего проекта я подумал / мне предложили использовать std::launder для перемещения элементов в векторе, где элементы перемещаютсятолько конструируемые (оператор заданного перемещения не определен).
Цель состоит в том, чтобы переместить последний элемент в заданную позицию i, а затем вытолкнуть первый.

Другими словами, полученный код будет чем-токак это (упрощенная версия для этой цели):

void foo(std::vector<my_type> &vec, std::size_t i) {
    my_type *el = vec.data() + i;
    el->~my_type();
    new (std::launder(el)) my_type{std::move(vec.back())};
    vec.pop_back();
}

Где my_type определяется как:

struct my_type { const int v; };

Цель использования std::launder состоит в том, чтобы установить барьер противвозможная оптимизация из-за того, что v в пределах my_type составляет const.Следовательно, чтобы иметь возможность перерабатывать память, зарезервированную для vec[i], чтобы заменить содержащийся объект другим экземпляром (фактически, я теоретически перемещаю последний элемент в другую позицию).

Это правильный подход / решение или это все еще UB, как это было бы, если бы я сделал что-то подобное, не возвращаясь к std::launder?

Насколько я понял, цель std::launder позволяет пользователям делать подобные вещи, и поэтому мне кажется, что приведенный выше фрагмент кода является законным.Но я не удивлюсь, если я ошибаюсь, поэтому я хотел бы получить отзыв от кого-то более опытного, чем я

--- РЕДАКТИРОВАТЬ

Точно так жеЯ также хочу поменять на элементы того же типа.
Полученный код должен выглядеть примерно так:

const auto tmp = std::move(vec[i]);
vec[i].~object_type();
new (std::launder(&vec[i])) object_type{std::move(vec[j])};
vec[j].~object_type();
new (std::launder(&vec[j])) object_type{std::move(tmp)};

Я вполне уверен, что если std::launder подойдетс первым примером этот также должен работать по аналогичным причинам.Я не прав?

1 Ответ

0 голосов
/ 31 декабря 2018

launder возвращает указатель на объект, который уже существует.

Там нет объекта.Вы просто уничтожили его в предыдущей строке.

Даже сам вызов launder является чистым чистым UB.

Для такого рода вещей launder необходим, когда вы доступ недавно созданный объект.Не тогда, когда вы его создаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...