Грокаем C++
9.36K subscribers
44 photos
1 video
3 files
572 links
Два сеньора C++ - Владимир и Денис - отныне ваши гиды в этом дремучем мире плюсов.

По всем вопросам (+ реклама) @ninjatelegramm

Менеджер: @Spiral_Yuri
Реклама: https://telega.in/c/grokaemcpp
Мы на TGstat: https://tgstat.ru/channel/@grokaemcpp/stat
Download Telegram
​​Передача владения
#новичкам

Захотелось совсем немного развить тему предыдущего поста.

В целом, мув семантика она не столько про оптимизацию(для этого есть например rvo/nrvo), сколько про передачу владения объектами. И то, что std::move ничего не мувает(а пытается сделать каст к rvalue reference) хорошо укладывается в эту концепцию. Данные не перемещаются, но вы говорите, что передаете владение этими данными.

void bar(std::vector<int>&& vec) {
// do nothing
}
void foo() {
std::vector<int> vec = {1, 2, 3};
bar(std::move(vec));
}


Здесь мы передаем владение вектором из foo в bar. Заметьте, что bar оперирует правой ссылкой, то есть никакие перемещающие конструкторы не вызывались. Но такая сигнатура говорит о главном: bar ожидает эксклюзивного права владения над этим вектором. Вы должны явно мувнуть объект, чтобы вызвать bar. И не важно, что он дальше bar с этим вектором делает. Может ничего не сделает, а может и использует как-то данные. Но так решил автор кода: вызов bar предполагает передачу ему владения вектором.

Другой пример:

std::vector<int> double_elements(std::vector<int> vec) {
for (auto& elem: vec) {
elem *= 2;
}
return vec;
}

void foo() {
std::vector<int> vec = {1, 2, 3};
{
auto doubled = double_elements(vec);
std::println("{}", doubled);
}
vec.push_back(4);
{
auto doubled = double_elements(std::move(vec));
std::println("{}", doubled);
}
}


Функция double_elements принимает вектор по значению и возвращает набор из удвоенных элементов.

Функция foo 2 раза вызывает удвоение значений элементов. По логике функции foo, ей еще нужен vec в целости и сохранности(нужно доложить в него элемент). Поэтому она и передает в первый раз vec в double_elements по значению. Но после второго вызова вектор ей больше не нужен. Поэтому можно передать владение им в double_elements: возможно он им распорядится лучше.

Еще одна вещь, которая подчеркивает передачу владения: moved-from объект практически никак в общем случае нельзя безопасно использовать, кроме как безопасно разрушить или переприсвоить(в комментах под прошлым постом более конкретно обсуждали этот момент). Даже если функция принимает rvalue reference, это не значит, что она не изменяет объект: возможно внутренние вызовы это делают.

Поэтому можно принять за правило, что, передав владение, вы больше физически не имеете права пользоваться объектом. Это как продав компанию, вы бы продолжили иметь то же влияние на нее. Нетушки. Либо крестик снимите, либо трусы наденьте. Либо передали владение и забыли, либо скопировали и дальше попользовались.

Give away what you don't need. Stay cool.

#cppcore #cpp11
18👍12🔥6