По факту здесь ничего сложного нет, просто есть небольшая путаница с lvalue и rvalue)) Даже если не углубляться в это в начале обучения, со временем все равно поймешь.
Если мы сразу передаем r-value, то, конечно же, будет просто одно перемещение, я тут имел ввиду, если мы будет передавать l-value через move: std::string str = "some long string"; .... add(std::move(str));
@@denisgluk431 Нет, не как return, тут все проще Смотри, у тебя есть какая-то функция, которая принимает какой-то параметр, и ты знаешь, что этот параметр в этой функции точно будет скопирован. Я привел пример с добавлением в вектор, но давай другой пример рассмотрим, может он будет проще для понимания: пусть у нас есть класс Person, у него есть поле имя: (тут важно, что std::string имеет конструктор перемещения) class Person { std::string name; // передаем по l-ссылке - тут нет копирования Person(const std::string &name) { // А тут копирование this->name = name; } }; Чтобы ты не передал в конструктор - у тебя всегда будет одно копирование. А раз ты неизбежно всегда создаешь копию объекта, то можно делать копию не в момент присваивания полю класса, а в момент передачи в параметр: class Person { std::string name; // Теперь тут создается копия Person(std::string name) { // А тут копию всегда перемещаем, это же копия, она исходный объект не поменяет this->name = std::move(name); } }; В первом случае - у нас было только одно копирование, во втором случае - одно копирование + одно перемещение. НО! теперь при передачи r-value, например так: std::string someString = "....."; Person p(std::move(someString)); копия будет создана путем конструктора перемещения, да + еще одно перемещение в момент присваивания полю: // случай с r-value Person(std::string name) // name = std::move(someString) (раз перемещение) { // А тут копию всегда перемещаем this->name = std::move(name); // (два перемещение) } И того, у нас два перемещения. Поэтому если твой объект умеет перемещаться, да еще его перемещение настолько дешевое (например просто переставляются указатели) - то ты можешь сказать, окей, хрен с ним, я пожертвую одним лишним перемещением (то есть я готов на то, что всегда будет хотя бы одно перемещение), зато мне не надо будет создавать две перегрузки для обработки случая для r-value. Вот, в целом, никакой магии. Надеюсь стало более понятно PS. 1. Можешь посмотреть объяснение от Ильи Мещерена (парень успел поработать в Гугле и Яндексе, сейчас параллельно преподает в МФТИ) - в одной из лекций по семантике перемещения (надо искать, так не помню, какая именно) 2. У Скотта Мейерса в книге "Эффективный и современный с++. 42 рекомендации..." глава 8.1 полностью посвящена этой теме
Здесь вообще все на поверхности. У тебя указатель на область памяти при std::move просто переносится а при копировании новый выделяется. Если говорить про стек тоже самое будет те же указатели и доп информация структур проплоцирлванных
00:09 - *идельную передачу (Perfect forwarding)
супер полезный канал
Видео было очень полезным, спасибо!
после этого видоса я задаюсь вопросом, а так ли я хочу изучать плюсы...
По факту здесь ничего сложного нет, просто есть небольшая путаница с lvalue и rvalue)) Даже если не углубляться в это в начале обучения, со временем все равно поймешь.
Астрологи объявили год годноты, количество крутого контента увеличолсь.
27:56 c rvalue будет 0 копирований и 1 перемещение, разве нет?
Если мы сразу передаем r-value, то, конечно же, будет просто одно перемещение, я тут имел ввиду, если мы будет передавать l-value через move:
std::string str = "some long string";
....
add(std::move(str));
@@PolevoysProgramming как это работает? так же, как return сделали? первый раз про такую фишку слышу
@@denisgluk431 Нет, не как return, тут все проще
Смотри, у тебя есть какая-то функция, которая принимает какой-то параметр, и ты знаешь, что этот параметр в этой функции точно будет скопирован. Я привел пример с добавлением в вектор, но давай другой пример рассмотрим, может он будет проще для понимания:
пусть у нас есть класс Person, у него есть поле имя: (тут важно, что std::string имеет конструктор перемещения)
class Person
{
std::string name;
// передаем по l-ссылке - тут нет копирования
Person(const std::string &name)
{
// А тут копирование
this->name = name;
}
};
Чтобы ты не передал в конструктор - у тебя всегда будет одно копирование. А раз ты неизбежно всегда создаешь копию объекта, то можно делать копию не в момент присваивания полю класса, а в момент передачи в параметр:
class Person
{
std::string name;
// Теперь тут создается копия
Person(std::string name)
{
// А тут копию всегда перемещаем, это же копия, она исходный объект не поменяет
this->name = std::move(name);
}
};
В первом случае - у нас было только одно копирование, во втором случае - одно копирование + одно перемещение. НО! теперь при передачи r-value, например так:
std::string someString = ".....";
Person p(std::move(someString));
копия будет создана путем конструктора перемещения, да + еще одно перемещение в момент присваивания полю:
// случай с r-value
Person(std::string name) // name = std::move(someString) (раз перемещение)
{
// А тут копию всегда перемещаем
this->name = std::move(name); // (два перемещение)
}
И того, у нас два перемещения.
Поэтому если твой объект умеет перемещаться, да еще его перемещение настолько дешевое (например просто переставляются указатели) - то ты можешь сказать, окей, хрен с ним, я пожертвую одним лишним перемещением (то есть я готов на то, что всегда будет хотя бы одно перемещение), зато мне не надо будет создавать две перегрузки для обработки случая для r-value.
Вот, в целом, никакой магии. Надеюсь стало более понятно
PS.
1. Можешь посмотреть объяснение от Ильи Мещерена (парень успел поработать в Гугле и Яндексе, сейчас параллельно преподает в МФТИ) - в одной из лекций по семантике перемещения (надо искать, так не помню, какая именно)
2. У Скотта Мейерса в книге "Эффективный и современный с++. 42 рекомендации..." глава 8.1 полностью посвящена этой теме
Ответ на последнее - нужно было в первых редакциях Си11. Потом прикрыли.
И в очередной раз разработчики C++ блестяще решили проблему, которую сами же и создали.)))
передал по ссылке...
Все это хорошо, но ничего не понятно, как это происходит на уровне ассемблера, на уровне регистров, стека
Здесь вообще все на поверхности. У тебя указатель на область памяти при std::move просто переносится а при копировании новый выделяется. Если говорить про стек тоже самое будет те же указатели и доп информация структур проплоцирлванных
Как компилятор захочет, так на ассемблере и будет реализовано
Сплошные костыли вместо вывода типов здорового человека.
🤝
Лайк за креатор, а то эмаксвимовские консольные сектанты надоели.