std :: переместить const std :: vector в лямбда-захват - PullRequest
0 голосов
/ 30 сентября 2018

Мотивация:

Я пытаюсь перевести std::vector<std::unique_ptr<some_type>> в другой поток через лямбда-захват.

Так как мне нужно, чтобы вектор не очищался при выполнении функциивыходит за рамки видимости, мне нужно взять его по значению (а не по ссылке).

Поскольку это вектор unique_ptrs, мне нужно переместить (а не скопировать) его в захват.

Я использую обобщенный лямбда-захват для перемещения вектора во время захвата.

Минимальная программа для иллюстрации концепции:

auto create_vector(){
    std::vector<std::unique_ptr<int>> new_vector{};
    new_vector.push_back(std::make_unique<int>(5));
    return std::move(new_vector);
}

int main() {
    const auto vec_const = create_vector();

    [vec=std::move(vec_const)](){
        std::cout << "lambda, vec size: " << vec.size() << std::endl;
    }();
}

Проблема:

Если я использую const локальный вектор, компиляция завершится неудачно из-за попытки скопировать unique_ptr s.Однако, если я удаляю квалификатор const, код компилируется и работает хорошо.

auto vec_const = create_vector();

Вопросы:

В чем причина этого?Является ли const отключением «подвижности» вектора?Почему?

Как мне обеспечить константность вектора в таком сценарии?

Последующие действия:

В комментариях и ответах упоминается, что константный тип не можетбыть перемещен из.Звучит разумно, однако ошибки компилятора не дают понять.В этом случае я ожидал бы одну из двух вещей:

  • std::move(vec_const) должен выдать ошибку о невозможности перехода из const (приведение его к rvalue).
  • Перемещение вектора-строитель говорит мне, что он отказывается принимать постоянные значения.

Почему этого не происходит?Почему вместо этого назначение, кажется, просто пытается скопировать unique_ptrs внутри вектора (что я и ожидал от конструктора копирования векторов)?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Когда вы перемещаете что-то из A в B, тогда действие перемещения обязательно должно означать, что A изменяется, поскольку после перемещения A может больше не иметь того, что было в A, изначально,В этом и заключается цель семантики перемещения: обеспечить оптимальную реализацию, поскольку объекту, от которого он был удален, можно изменять: его содержимое переносится каким-то быстрым и загадочным образом в B, оставляя A в некотором действительном, ноне указано, состояние.

Следовательно, по определению, A не может быть const.

0 голосов
/ 30 сентября 2018

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

Итак, да: объект const нельзя (и не следует) перемещать.Это изменит исходный объект, что делает его const пустым.

В этом случае vector не имеет vector(const vector&&), только vector(vector &&) (конструктор перемещения) и vector(const vector &) (конструктор копирования).).

Разрешение перегрузки будет связывать вызов только с аргументом const vector с последним (чтобы не нарушалась правильность const), поэтому это приведет к копированию содержимого.

Согласен: ошибкаотчетность отстой.Трудно создать отчет об ошибке vector, когда вы столкнетесь с проблемой unique_ptr.Вот почему весь хвост required from ...., required from ... стирает представление.

Исходя из вашего вопроса и вашего кода, я могу сказать, что вы не полностью понимаете материал семантики перемещения:

  • вы не должны move возвращать значение;возвращаемое значение уже является r-значением, поэтому нет смысла.
  • std::move на самом деле ничего не перемещает, оно только изменяет квалификатор переменной, из которой вы хотите «перейти», так что правильный получатель можетбыть выбранным (используя «обязательные» правила).Это принимающая функция, которая фактически изменяет содержимое исходного объекта.
...