Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 11:13
Оценка: 6 (1) :)
Изучаю тут С++ для преподавания студентам.
И столкнулся с одной проблемой: не могу найти простого вменяемого примера для объяснения семантики переноса.
Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.
Но в книгах:
Джоссатис. Стандартная библиотека С++11
Стенли Липпман (Лажойе, Му). Язык программирования С++.
Стивен Прата. Язык программирования С++. Лекции и упражнения.
Примеры несколько расплывчаты, как-то мутноваты.

Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?
Особенно обращаюсь к Кодту и Павлу Кузнецову — может быть вам уже приходилось это использовать и/или объяснять?
Буду весьма признателен.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Пример по семантике переноса
От: jazzer Россия Skype: enerjazzer
Дата: 26.08.14 11:26
Оценка: +3
Здравствуйте, LaptevVV, Вы писали:

LVV>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?


std::vector. Все понимали с первого слова.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Пример по семантике переноса
От: anatoly1  
Дата: 26.08.14 11:37
Оценка: 1 (1)
Скорее всего там не пример нужен.
Полагаю, сначала нужно разобраться с rvalue-ссылками, а затем понять как работает функция swap на их основе.
И вполне возможно, что студентам эту тему можно не рассказывать. И без этих знаний можно писать программы на С++.
Re[2]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 11:45
Оценка:
Здравствуйте, anatoly1, Вы писали:

A>Скорее всего там не пример нужен.

A>Полагаю, сначала нужно разобраться с rvalue-ссылками, а затем понять как работает функция swap на их основе.
A>И вполне возможно, что студентам эту тему можно не рассказывать. И без этих знаний можно писать программы на С++.
Ну, можно и без виртуальности писать... Но ведь рассказываем жеж...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 11:48
Оценка:
Здравствуйте, jazzer, Вы писали:

LVV>>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?


J>std::vector. Все понимали с первого слова.

Что вектор?
Правильно ли я тебя понимаю,
что можно рассматривать использование динамической памяти вектором с использованием unique_ptr — как некий аналог семантики переноса?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Пример по семантике переноса
От: uzhas Ниоткуда  
Дата: 26.08.14 11:55
Оценка: 1 (1) +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.


так как я изначально вопрос не понял, то сразу рождается совет: ни в коем случае не рассматривай move semantic на примере с файлами
возьми что-нибудь из мира C++, пусть будет std::vector. не усложняй и без того сложную тему
Re[2]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 12:02
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, LaptevVV, Вы писали:


LVV>>Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.


U>так как я изначально вопрос не понял, то сразу рождается совет: ни в коем случае не рассматривай move semantic на примере с файлами

U>возьми что-нибудь из мира C++, пусть будет std::vector. не усложняй и без того сложную тему
Я и не рассматриваю.
Вот как раз про вектор — проясните, что тут имеется ввиду.
У стандартного вектора — семантика копирования.
В каких ситуациях может понадобиться семантика переноса?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Пример по семантике переноса
От: uzhas Ниоткуда  
Дата: 26.08.14 12:10
Оценка: 6 (1)
Здравствуйте, LaptevVV, Вы писали:


LVV>Вот как раз про вектор — проясните, что тут имеется ввиду.

LVV>У стандартного вектора — семантика копирования.
LVV>В каких ситуациях может понадобиться семантика переноса?

какой у тебя вообще уровень понимания ?
рекомендую начать с вики или SO: http://stackoverflow.com/questions/3106110/what-are-move-semantics
Re[4]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 12:20
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, LaptevVV, Вы писали:



LVV>>Вот как раз про вектор — проясните, что тут имеется ввиду.

LVV>>У стандартного вектора — семантика копирования.
LVV>>В каких ситуациях может понадобиться семантика переноса?

U>какой у тебя вообще уровень понимания ?


Ну, например, что такое ленивые вычисления — я прекрасно понимаю. И могу реализовать.
Проблем при чтении Александреску — не испытывал...
U>рекомендую начать с вики или SO: http://stackoverflow.com/questions/3106110/what-are-move-semantics
Спасибо, посмотрю.
Вопрос не в том, что я сам не понимаю. Вопрос придумать простой и понятный пример для объяснения студентам.
Вот с виртуальностью я долго мучился с примерами, пока не нашел пример у Шамиса в его книжке по С++Builder — очень просто и понятный...
И студенты с тех пор — тоже прекрасно СРАЗУ усваивают.
Вот и для семантики перехода хотелось бы придумать-поиметь аналогичный простой пример.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Пример по семантике переноса
От: jazzer Россия Skype: enerjazzer
Дата: 26.08.14 12:22
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, jazzer, Вы писали:


LVV>>>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?


J>>std::vector. Все понимали с первого слова.

LVV>Что вектор?
LVV>Правильно ли я тебя понимаю,
LVV>что можно рассматривать использование динамической памяти вектором с использованием unique_ptr — как некий аналог семантики переноса?

Ну все знают, что вектор — это по сути просто указатель куда-то в кучу и красивый интерфейс к нему.
Поэтому рассматриваешь передачу вектора по значению в стандартном С++98 (через конструктор копирования по константной ссылке), обсуждаешь, почему такое не используется (потому что ненужная работа производится), а потом говоришь, что можно было бы передавать без потерь в скорости, если бы можно было просто перекинуть владение буфером в куче от одного объекта другому. Но что нормального способа это сделать в С++98 не было без специальных телодвижений (типа Boost.Move), потому что ты не знаешь, что тебе по константной ссылке пришло — объект, у которого можно все забрать или нормальный объект, который еще может использоваться где-то и должен оставаться нетронутым. А в С++11 есть rvalue-ссылки, которые автоматом распознают, когда такое можно делать, и просто перекидывают указатель.

А unique_ptr сам по себе такой же, просто у него вообще копирование запрещено.

Хотя, возможно, я неправильно понял твой вопрос.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 26.08.14 12:32
Оценка:
Здравствуйте, jazzer, Вы писали:

LVV>>Правильно ли я тебя понимаю,

LVV>>что можно рассматривать использование динамической памяти вектором с использованием unique_ptr — как некий аналог семантики переноса?

J>Ну все знают, что вектор — это по сути просто указатель куда-то в кучу и красивый интерфейс к нему.

J>Поэтому рассматриваешь передачу вектора по значению в стандартном С++98 (через конструктор копирования по константной ссылке), обсуждаешь, почему такое не используется (потому что ненужная работа производится), а потом говоришь, что можно было бы передавать без потерь в скорости, если бы можно было просто перекинуть владение буфером в куче от одного объекта другому. Но что нормального способа это сделать в С++98 не было без специальных телодвижений (типа Boost.Move), потому что ты не знаешь, что тебе по константной ссылке пришло — объект, у которого можно все забрать или нормальный объект, который еще может использоваться где-то и должен оставаться нетронутым. А в С++11 есть rvalue-ссылки, которые автоматом распознают, когда такое можно делать, и просто перекидывают указатель.

J>А unique_ptr сам по себе такой же, просто у него вообще копирование запрещено.


J>Хотя, возможно, я неправильно понял твой вопрос.

Спасибо, помедитирую.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Пример по семантике переноса
От: uzhas Ниоткуда  
Дата: 26.08.14 12:34
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Вопрос не в том, что я сам не понимаю. Вопрос придумать простой и понятный пример для объяснения студентам.


могу дать такие советы:
1) взять чье-либо объяснение и его разжевать. это проще, чем что-то самому выдумывать
2) для меня move — это аналог swap, просто реализованный на уровне языка (пусть и грубая аналогия, но для меня она первична). теперь задача сводиться к тому, чтобы объяснить зачем нужен swap =)
Re[5]: Пример по семантике переноса
От: saf_e  
Дата: 26.08.14 12:38
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, uzhas, Вы писали:


U>>Здравствуйте, LaptevVV, Вы писали:



LVV>>>Вот как раз про вектор — проясните, что тут имеется ввиду.

LVV>>>У стандартного вектора — семантика копирования.
LVV>>>В каких ситуациях может понадобиться семантика переноса?

U>>какой у тебя вообще уровень понимания ?

LVV>
LVV>Ну, например, что такое ленивые вычисления — я прекрасно понимаю. И могу реализовать.
LVV>Проблем при чтении Александреску — не испытывал...
U>>рекомендую начать с вики или SO: http://stackoverflow.com/questions/3106110/what-are-move-semantics
LVV>Спасибо, посмотрю.
LVV>Вопрос не в том, что я сам не понимаю. Вопрос придумать простой и понятный пример для объяснения студентам.
LVV>Вот с виртуальностью я долго мучился с примерами, пока не нашел пример у Шамиса в его книжке по С++Builder — очень просто и понятный...
LVV>И студенты с тех пор — тоже прекрасно СРАЗУ усваивают.
LVV>Вот и для семантики перехода хотелось бы придумать-поиметь аналогичный простой пример.

Попробуйте рассмотреть на примере std::swap для двух векторов (ну, или любых других объектов).

Ну и, как вариант, эстафетное владение. Т.е. unique_ptr или подобный объект.
Re: Пример по семантике переноса
От: Кодт Россия  
Дата: 26.08.14 13:03
Оценка: 24 (4)
Здравствуйте, LaptevVV, Вы писали:

LVV>Изучаю тут С++ для преподавания студентам.

LVV>И столкнулся с одной проблемой: не могу найти простого вменяемого примера для объяснения семантики переноса.

Эстафетное владение указуемым объектом (std::auto_ptr). В одном месте создали, в другое отдали, в старом забыли.

Физический пример: тачка с песком.
Передача по значению — это сделать новую тачку и насыпать туда такой же песок, как в исходной. Будет вдвое больше песка.
Передача по ссылке — отдать свою тачку в аренду.
Перемещение — высыпать песок из одной тачки в другую. Старую тачку выкинуть не немедленно, а в наиболее подходящий момент.

Можешь предложить студентам творческое задание: как передавать внутрь функции или возвращать из функции тяжеловесный объект (скажем, рукодельный вектор), не прибегая ни к копированию, ни к подсчёту ссылок. (А то на shared_ptr любой дурак сделает).
Скажи, что это нужно, скажем, для библиотеки линейной алгебры.
Перекуём баги на фичи!
Re: Пример по семантике переноса
От: zaufi Земля  
Дата: 26.08.14 15:09
Оценка: :))
Здравствуйте, LaptevVV, Вы писали:

LVV>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?

LVV>Буду весьма признателен.

Голливудский сценарий:

Простой инженер КБ, будучи завербованным агентом иностранной разведки, выносит с работы USB флэшку (объект) набитую сверхсекретными чертежами и спецификациями. Он отдает (move) ее агенту, получает чемодан денег и оба скрываются во мраке ночи (ибо копировать 100500 гигов с флэшки в ноут агента очень долго, да и флэшка (как носитель) не стоит такого риска). Агент сам не может вывезти ее через границу, поэтому одтает (move) флэшку (объект) дип. курьеру в консульстве своей страны. В полете у курьера случается сердечный приступ, а флэшка (объект) попадает (move) в руки стюардессы -- агента военной разведки третьей страны, которая подсыпала что-то в стакан курьеру. Сразу после приземления, стюардесса едет на конспиративную квартиру, где происходит копирование (та самая процедура, которая занимает 100500 минут) этой флэшки на несколько других носителей. После чего, флэшка уже не нужна и уничтожается (delete flashka.

Дальше, по закону жанра, в кадре появляется главный герой, который до конца фильма мочит (terminate) всех, кто хоть что-то знает про информацию с флэшки %)
перемещая (move) всех на своем пути в мир иной %)
Re[2]: Пример по семантике переноса
От: uzhas Ниоткуда  
Дата: 26.08.14 15:22
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Дальше, по закону жанра, в кадре появляется главный герой, который до конца фильма мочит (terminate) всех, кто хоть что-то знает про информацию с флэшки %)

Z>перемещая (move) всех на своем пути в мир иной %)

есть соответствующий драфт на включение std::move_to_null в стандарт языка и его небросающей версии в случае std::terminate
читать здесь http://www.open-std.org/jtc1/sc22/wg21/ и здесь http://www.open-std.org/jtc1/sc22/wg21/docs/mailings/
Re[3]: Пример по семантике переноса
От: rus blood Россия  
Дата: 26.08.14 19:59
Оценка: 1 (1) +1
Здравствуйте, LaptevVV, Вы писали:

LVV>В каких ситуациях может понадобиться семантика переноса?


Возьми как пример вектор строк.
И ситуацию, когда этот вектор должен выполнить релокацию — добавили новую строку, а места в буфере вектора для нее нет.
Как выполняется релокация с обычным копированием:
1. создается новый буфер увеличенного размера,
2. строки из старого буфера копируются в новый (создаются копии),
3. строки в старом буфере удаляются,
4. удаляется старый буфер.

Копирование одной строки на шаге 2 влечет создание буфера в новом объекте-строке и копирование содержимого из старого в новый.
При этом, буфер старого объекта-строки просто удаляется на шаге 3.

Вместо этого, новый объект-строка мог бы просто забрать себе адрес массива символов старого объекта, а указатель на этот массив в старом объекте-строке просто занулить, чтобы деструктор не удалил этот массив.
Это и делает семантика переноса класса строки.
Имею скафандр — готов путешествовать!
Re: Пример по семантике переноса
От: Abyx Россия  
Дата: 26.08.14 21:06
Оценка: 20 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Изучаю тут С++ для преподавания студентам.

LVV>И столкнулся с одной проблемой: не могу найти простого вменяемого примера для объяснения семантики переноса.
LVV>Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.

как мне кажется, тут надо начинать с категорий выражений — всякие xvalue/prvalue
потом изучать как передаются параметры в конструкторы и прочие функции
потом становится понятно что если в функцию передали неконстантную ссылку, то мы можем взять из нее одни данные, а взамен положить другие
а дальше и перенос становится логичным и понятным

или может стоит сначала рассказать про замену копирования на swap

void f(X& a) {
  X b = ...;
  swap(a, b);
}


а потом сказать что вместо вызова swap руками есть мув-семантика
void f(X& a) {
  X b = ...;
  a = move(b);
}
In Zen We Trust
Re[5]: Пример по семантике переноса
От: VladFein США  
Дата: 26.08.14 21:59
Оценка: +2
Здравствуйте, LaptevVV, Вы писали:

LVV>Вопрос не в том, что я сам не понимаю. Вопрос придумать простой и понятный пример для объяснения студентам.


Есть гипотеза что тот, кто не может объяснить, сам не до конца понимает.

Ну и анекдотическое приложение к этому:
— Я ему объяснял, объяснял, уже сам понял, а он — никак.
Re[2]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 27.08.14 04:30
Оценка:
Здравствуйте, Abyx, Вы писали:

A>или может стоит сначала рассказать про замену копирования на swap

A>а потом сказать что вместо вызова swap руками есть мув-семантика
Вот! Кажись то, что нужно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Пример по семантике переноса
От: mefrill Россия  
Дата: 27.08.14 06:03
Оценка: 10 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?

LVV>Особенно обращаюсь к Кодту и Павлу Кузнецову — может быть вам уже приходилось это использовать и/или объяснять?
LVV>Буду весьма признателен.

А мне кажется, с методической точки зрения, лучше взять в качестве объекта для переноса std::string. Вот, почему раньше нехорошо было писать такие функции:
std::string foo() {
  std::string result = "Hello, World!";
  return result;
}


Потому, что создавалось два объекта std::string: один во фрейме вызова foo, а другой -- копия этого объекта для возврата результата вызова. Поэтому, раньше делали, например, так:
void foo(std::string& result) {
  result = "Hello, World!";
}


Сейчас можно так не делать, т.к. компилятор умный, он видит в первом варианте foo, что переменная result больше не нужна, поэтому ее можно изменить в целях оптимизации. Формальное определение такого изменения -- это преобразование к r-value ссылке. Для r-value ссылки у std::string есть специальный конструктор, который не резервирует новую память для хранения "Hello, World!", а берет из параметра конструктора (т.е. из r-value ссылки на существующий объект) имеющуюся у него память, ту же строку "Hello, World!". Т.к. на два объекта типа std::string не может быть одной памяти, содержащей "Hello, World!" (знаю, есть (были) библиотеки, где это не так, но студентам не нужно об этом рассказывать, если не спросят), то модифицируется содержимое объекта из параметра: у него нагло забирается указатель на память "Hello, World!". Выделения новой памяти нет, копирования нет -- все оптимально.

Если объект для перемещения, это не возвращаемый параметр, а переменная, которая будет доступна после перемещения, например:
....
std::string str1 = "Hello, World!";
std::string str2 = str1;
....

// где-то здесь можно использовать str1
}


то такие вопросы студентам:
1. Как подсказать компилятору, что при инициализации str2 надо не копировать данные из str1, а переместить?
2. Что будет с str1 после перемещения и можно ли этот объект использовать снова?
Re[6]: Пример по семантике переноса
От: jazzer Россия Skype: enerjazzer
Дата: 27.08.14 06:10
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, LaptevVV, Вы писали:


LVV>>Вопрос не в том, что я сам не понимаю. Вопрос придумать простой и понятный пример для объяснения студентам.


U>могу дать такие советы:

U>1) взять чье-либо объяснение и его разжевать. это проще, чем что-то самому выдумывать

Так он, вроде, именно "чье-либо объяснение" и просит

U>2) для меня move — это аналог swap, просто реализованный на уровне языка (пусть и грубая аналогия, но для меня она первична). теперь задача сводиться к тому, чтобы объяснить зачем нужен swap =)


Ну да, анизотропный swap
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Пример по семантике переноса
От: uzhas Ниоткуда  
Дата: 27.08.14 06:56
Оценка: :)
Здравствуйте, jazzer, Вы писали:

J>Так он, вроде, именно "чье-либо объяснение" и просит


во-первых, спрашивать надо у гугла
во-вторых, ctrl-F -> придумать
Re: Пример по семантике переноса
От: lxa http://aliakseis.livejournal.com
Дата: 27.08.14 12:11
Оценка: +1 :)
Чем-то напоминает.
Re[3]: Пример по семантике переноса
От: MasterZiv СССР  
Дата: 27.08.14 15:33
Оценка: 10 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>В каких ситуациях может понадобиться семантика переноса?


При оптимизации операции swap и её подобных.

Про std::vector я уверен имелось в виду про оптимизацию переноса элементов в новое физическое хранилище при изменении размеров вектора.

Я, например, тоже с таким сталкивался, делал объект "набор данных БД", состоящий из строк из реляционных таблиц.
При этом типичная проблема -- это заполнение набора данных из запроса, размер строк предопределён сразу после выполнения запроса,
а размер всего набора данных неизвестен. Реализуется схема работы "выделяем буфер под n строк, читаем в него, пока не заполнится,
затем если переполняется, выделяем новый буфер в 2*n и копируем (перемещаем) уже прочитанное туда и продолжаем заполнять элементы
в конец, пока снова не достигнем границы, и так далее".
Делал это сам, руками (хранил ссылки на строки, владение передавалось от одного объекта "набор данных" другому), естественно,
никакой move semantics не было, а это -- самое оно, что нужно в таком случае.

Ну и все подобные алгоритмы подойдут, чтение в память строк текста из файла бесконечной длины,
приём сообщений в локальный буфер, и т.п.
Re[2]: Пример по семантике переноса
От: MTD https://github.com/mtrempoltsev
Дата: 27.08.14 15:55
Оценка: 58 (5) +2 :))
Здравствуйте, Кодт, Вы писали:

К>Физический пример: тачка с песком.

К>Передача по значению — это сделать новую тачку и насыпать туда такой же песок, как в исходной. Будет вдвое больше песка.
К>Передача по ссылке — отдать свою тачку в аренду.
К>Перемещение — высыпать песок из одной тачки в другую. Старую тачку выкинуть не немедленно, а в наиболее подходящий момент.

Удачней пример с телевизором:
По значению — вот тебе точно такой-же телевизор, бери и смотри. Можешь каналы переключать, мне все равно.
По ссылке — садись, вместе будем смотреть, при этом если программу кто-то переключит, то все смотреть будут другой канал.
Перемещение — да забирай ты этот телевизор себе, надоел он мне.
Re: коротко о мув семантике
От: cthsq  
Дата: 28.08.14 13:42
Оценка: 191 (9)
перепечатано из
http://stackoverflow.com/questions/3106110/what-are-move-semantics

Походу самый простой способ понять move семантику — это на примере кода. Давайте начнём с очень простого класса строк, который всего лишь хранит указатель на размещённый в куче блок памяти:

#include <cstring>
#include <algorithm>

class string
{
    char* data;

public:

    string(const char* p)
    {
        size_t size = strlen(p) + 1;
        data = new char[size];
        memcpy(data, p, size);
    }


Так как мы решили самостоятельно управлять памятью, нам нужно следовать Правилу трёх. Пока опустим оператор присваивания и напишем деструктор и конструктор копирования:

    ~string()
    {
        delete[] data;
    }

    string(const string& that)
    {
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        memcpy(data, that.data, size);
    }


Параметр конструктора const string& подходит ко всем выражениям с типом string, что позволяет нам создавать копии в следующих примерах:

string a(x);                                    // Line 1
string b(x + y);                                // Line 2
string c(some_function_returning_a_string());   // Line 3


Терь наступает ключевой момент в понимании мув семантики. Обратите внимание, что только в первой строке, где мы копировали x, глубокая копия на самом деле необходима, потому, что мы можем использовать x позже, и будем сильно удивлены, если x как то изменится. Заметили как я только что 3 раза сказал x (четыре, если считать это предложение) и это каждый раз означало тот же объект? Мы называем такие выражения, как x "lvalue"

Аргументы в строках 2 и 3 это не lvalue, а rvalue, поскольку эти строковые объекты не имеют имён, и вызывающий код не имеет возможности дальнейшего их использования. rvalue это временные объекты, которые уничтожаются в конце выражения. Это важно, поскольку во время инициализации b и c мы можем делать что угодно с исходными строками и вызывающий код об этом никак не узнает.

C++0x предаставляет новый механизм называющийся "rvalue reference" который помимо прочего, через перегрузку функций, позволяет нам определять что аргумент является rvalue. Всё что, нам для этого надо — это написать конструктор с параметром
ссылкой на rvalue. Внутри этого конструктора мы можем делать всё что угодно с исходным значением, пока оно остаётся в каком то валидном состоянии

    string(string&& that)   // string&& это rvalue ссылка на string
    {
        data = that.data;
        that.data = 0;
    }


Ну и что мы тут сделали? Вместо глубокой копии данных из кучи мы просто скопировали указатели и установили оригинальный указатель в null. В результате мы "стащили" данные, которые изначально принадлежали исходной строке. Опять же ключевой момент в том что вызывающий код ни при каких обстоятельствах не узнает, что исходный объект был изменён. Поскольку на самом деле мы не создавали копию, такой конструктор называется "move constructor". Его работа заключается в том чтобы, вместо копирования, просто переместить ресурсы из одного объекта в другой.

Поздравляю, вы только что поняли основы move семантики. Давайте продолжим реализовав оператора присваивания. Если вы пока не знакомы с
copy and swap идиомой то почитайте и возвращайтесь назад, поскольку это довольно грамотный подход, для того чтобы обеспечивать безопасность исключений в c++

    string& operator=(string that)
    {
        std::swap(data, that.data);
        return *this;
    }


Опа. Ну и чё это? Где здесь "rvalue reference"? кто то спросит. А я отвечу "А оно нам тут и не надо )"

Заметьте мы тут передали параметр по значению, так чтобы он инициализировался как любой другой строковый объект. Ну и как он будет инициализироваться? Раньше, во времена C++98, ответ был бы "с помощью конструктора копирования". В C++0x компилятор уже выбирает между конструктором копирования и конструктором переноса на основе того является аргумент lvalue или rvalue.

Так, если вы напишете a = b "that" будет инициализировано конструктором копирования (по тому, что b это lvalue) и оператор присваивания обменяется содержимым с только что созданной копией. Вот и всё определение идиомы copy and swap — создать копию, обменяться содержимым с копией, а потом избавиться от копии выходом из области видимости. Здесь больше ничего нового.

Но если вы напишете a = x + y "that" будет инициализировано с помощью конструктора переноса (т.к. x + y это rvalue), таким образом глубокая копия не создаётся, только переходит владение. "that" всё ещё независимый от аргументов объект, но его создание было дешевым, так как данные из кучи не копировались, а только меняли владельца.

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




Ну и слегка поподробнее:

Введение

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

1. Замена дорогого копирования дешевой сменой владельца. Обратите внимание, что если объект не управляет по крайней мере одним внешним ресурсом (непосредственно, или через другой объект его член) семантика копирования не представляет никакого преимущества перед семантикой копирования. В этом случае копирование и перемещение — одно и то же:

class cannot_benefit_from_move_semantics
{
    int a;        // перемещение инта тоже самое что и копирование инта
    char d[64];   // перемещение массива символов тоже самое что и копирование массива символов

    // ...
};


2. Реализация безопасных "move-only" типов; это типы для которых копирование не имеет смысла а перемещение имеет. Например файловые хендлеры, смартпоинтеры с семантикой уникального владения.

Что значит перемещение?
Стандартная библиотека С++98 предоставляет смартпоинтер с семантикой уникального владения std::auto_ptr<T>, который гарантирует что динамически размещённый объект будет удалён даже в случае исключения:

{
    std::auto_ptr<Shape> a(new Triangle);
    // ...
    // arbitrary code, could throw exceptions
    // ...
}   // <--- when a goes out of scope, the triangle is deleted automatically


необычность auto_ptr состоит в его "копирующем" поведении:

auto_ptr<Shape> a(new Triangle);

      +---------------+
      | triangle data |
      +---------------+
        ^
        |
        |
        |
  +-----|---+
  |   +-|-+ |
a | p | | | |
  |   +---+ |
  +---------+

auto_ptr<Shape> b(a);

      +---------------+
      | triangle data |
      +---------------+
        ^
        |
        +----------------------+
                               |
  +---------+            +-----|---+
  |   +---+ |            |   +-|-+ |
a | p |   | |          b | p | | | |
  |   +---+ |            |   +---+ |
  +---------+            +---------+


Заметьте, что при инициализации b переменной a треугольник не копируется, вместо этого передаётся владение треугольником из a в b. Как ещё говорят "a переместилось в b" или "треугольник переместился из a в b". Это может звучать странно, поскольку треугольник сам по себе оставался на том же месте в памяти.

Переместить объект означает передать владение какого либо ресурса, которым он управлял, в другой объект.

Конструктор копирования auto_ptr скорее всего выглядит как то так (немного упрощённо):
auto_ptr(auto_ptr& source)   // Обратите внимание нету const
{
    p = source.p;
    source.p = 0;   // терь source больше не владеет объектом
}


Dangerous and harmless moves

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

auto_ptr<Shape> a(new Triangle);   // создаём треугольник
auto_ptr<Shape> b(a);              // перемещаем из a в b
double area = a->area();           // неопределенное поведение


But auto_ptr is not always dangerous. Factory functions are a perfectly fine use case for auto_ptr:
Но auto_ptr не всегда опасны. Фабричные функции — отличный юзкейс для auto_ptr:

auto_ptr<Shape> make_triangle()
{
    return auto_ptr<Shape>(new Triangle);
}


auto_ptr<Shape> c(make_triangle());      // перемещаем временный объект в c
double area = make_triangle()->area();   // всё безопасно


Обратите внимание, как оба примера следуют одной и той же семантике:

auto_ptr<Shape> variable(expression);
double area = expression->area();


И в то время как один из них вызывает неопределенное поведение другой нет. Так какая разница между expressions и make_triangle()? Они что, разного типа? Не, одного. Но они разных value категорий.


Value категории

Очевидно должно быть глубокое различие между переменной auto_ptr expression и выражением make_triangle(), которое является вызовом функции, возвращающей auto_ptr по значению, которая создаёт новый временный auto_ptr объект каждый раз, когда она вызывается. expression это пример lvalue, в то время как make_triangle() — пример rvalue.

Перемещение из lvalue как в пример выше опасно, потому, что мы можем позже вызвать функцию-член через a, что приведёт к неопределённому поведению. С другой стороны перемещение из rvalue совершенно безопасно потому, что после того как конструктор копирования завершил свою работу мы не можем снова использовать временный объект. Если мы просто напишем make_triangle() ещё раз, мы получим новый временный объект. Фактически временный объект, из которого производится перемещение уничтожается на следующей строке
auto_ptr<Shape> c(make_triangle());
                                  ^ временный объект, из которого производится перемещение умирает прямо тут


Обратите внимание, что буквы l и r исторически произошли от левой(left-hand) и правой(right-hand) стороны присваивания.
В С++ это больше не так потому, что существуют lvalue, которые не могут появиться с левой стороны присваивания (навроде массивов и типов определённых пользователем без оператора присваивания) и rvalue которые могут

Ссылки на rvalue

Теперь мы понимаем, что перемещение из lvalue потенциально опасно, а перемещение из rvalue нет. Если бы язык С++ давал возможность отличить lvalue аргументы от rvalue аргументов мы можем либо полностью запретить перемещение из lvaluе, либо по крайней мере сделать перемещение из lvalue явным в месте вызова, и таким образом мы избегаем случайного перемещения.

С++11 решает эту проблему ссылками на rvalue. rvalue ссылки это новый вид ссылок, которые связываются только с rvalue объектами, и имеют синтаксис X&&. Старые добрые X& ссылки теперь называются lvalue ссылками. (Заметьте что X&& это не ссылки на ссылки, такой штуки в С++ нету)

Если мы добавим ещё и const, то получим уже четыре различных типа ссылок. Тут перечислены виды выражений типа X, с которыми они могут быть связаны (bind).

            lvalue   const lvalue   rvalue   const rvalue
---------------------------------------------------------              
X&          да
const X&    да       да             да       да
X&&                                 да 
const X&&                           да       да


На практике вы можете забыть про X&&. От rvalue только для чтения мало толку.

rvalue ссылки X&& это новый вид ссылок, которые привязываются (binds) только rvalue.


Неявные преобразования

rvalue ссылки прошли через нескольких версий. С версии 2.1 ссылки X&& также связываются со всеми value категориями отличного типа Y, если предоставлен способ неявного преобразования из Y в X. В этом случае создаётся временный объект типа X и rvalue ссылка связывается с этим временным объектом:

void some_function(std::string&& r);

some_function("hello world");

В примере, приведенном выше, "hello world" это lvalue имеющее тип const char[12]. Так как тут неявное преобразование из const char[12] через const char* в std::string, создаётся временный объект типа std::string, и r с ним связывается. Это один из случаев, когда разница между rvalues (выражениями) и временными объектами немного размыта.

Конструкторы перемещения

Полезный пример функции с параметром X&& это конструктор перемещения X::X(X&& source. Он предназначен для передачи владения ресурсом из объекта source в текущий объект.

В С++11 std::auto_ptr<T> заменен на std::unique_ptr<T>, который имеет преимущество rvalue ссылок. Мы тут создадим и обсудим упрощенную версию unique_ptr.
Сперва мы инкапсулируем сырой указатель и перегрузим операторы -> и *, так чтобы наш класс вёл себя как указатель:

template<typename T>
class unique_ptr
{
    T* ptr;

public:

    T* operator->() const
    {
        return ptr;
    }

    T& operator*() const
    {
        return *ptr;
    }

Конструктор получает объект во владение, а деструктор его удаляет:
    explicit unique_ptr(T* p = nullptr)
    {
        ptr = p;
    }

    ~unique_ptr()
    {
        delete ptr;
    }


Теперь интересная часть — Конструктор перемещения:
    unique_ptr(unique_ptr&& source)   // rvalue ссылка
    {
        ptr = source.ptr;
        source.ptr = nullptr;
    }


Этот конструктор перемещения работает так же как и конструктор копирования auto_ptr, но он применим только к rvalue:
unique_ptr<Shape> a(new Triangle);
unique_ptr<Shape> b(a);                 // error
unique_ptr<Shape> c(make_triangle());   // okay


Вторая строчка не компилируется потому что a это lvalue, а параметр unique_ptr&& принимает только rvalue. Это именно то, чего мы хотели. Опасное перемещение никогда больше не произойдёт неявно. Третья строка компилируется без проблем, так как make_triangle() это rvalue. Конструктор перемещения преренесёт владение от временного объекта в c. Опять же это то что нам нужно.

Перемещающий конструктор передаёт владение управляемым ресурсом в текущий объект


Перемещающий оператор присваивания

Последняя недостающая часть это Перемещающий оператор присваивания. Его задача состоит в освобождении старого ресурса и захвате нового ресурса из аргумента:

    unique_ptr& operator=(unique_ptr&& source)   // rvalue ссылка
    {
        if (this != &source)    // не присваиваем самому себе
        {
            delete ptr;         // освобождаем старый

            ptr = source.ptr;   // захватываем новый
            source.ptr = nullptr;
        }
        return *this;
    }
};

Тут реализация перемещающего оператора присваивания дублирует логику деструктора и перемещающего конструктора.
Помните про copy-and-swap идиому? Она также может быть применена к семантике перемещения как move-and-swap идиома

    unique_ptr& operator=(unique_ptr source)   // здесь нету ссылки
    {
        std::swap(ptr, source.ptr);
        return *this;
    }
};


Теперь source это переменная типа unique_ptr, она должна быть инициализирована конструктором перемещения; таким образом аргумент будет перемещен в параметр. Всё ещё требуется чтобы аргумент был rvalue, потому что конструктор перемещения сам по себе имеет параметр ссылку на rvalue. Когда порядок выполнения достигает закрывающей фигульной скобки оператора=, source выходит из области видимости и уничтожается, автоматически освобождая старый ресурс.

Перемещающий оператор присваивания передаёт владение управляемым ресурсом в текущий объект и освобождает старый ресурс. Идиома move-and-swap облегчает реализацию.


Перемещение из lvalue

Иногда нам хотелось бы переместить из lvalue. То есть мы хотели бы чтобы компилятор обращался с lvalue как будто это rvalue, так чтоб он мог вызвать конструктор перемещения, пусть это было бы потенциально небезопасно. Для этих целей С++11 предлагает функцию стандартной библиотеки std::move, которая находится в заголовке <utility>. Имя выбрано слегка неудачно, потому что std::move всего лишь приводит lvalue к rvalue, и ничего никуда не перемещает. Эта функция всего лишь делает возможным перемещение. Возможно она должна была называться std::cast_to_rvalue или std::enable_move, но в настоящее время название уже устаканилось.



Тут показано как вы можете перемещать из lvalue явно:

unique_ptr<Shape> a(new Triangle);
unique_ptr<Shape> b(a);              // всё ещё ошибка
unique_ptr<Shape> c(std::move(a));   // okay


Обратите внимание, что после третьей строки a больше не владеет треугольником. Это нормально, поскольку явно написав std::move(a) мы сделали ясными наши намерения: "Уважаемый конструктор, делай что захочешь с a, чтобы инициализировать c; Меня а больше не интересует."

std::move(some_lvalue) приводит lvalue к rvalue, и делает возможным дальнейшее перемещение.


Xvalue

Обратите внимание, что хотя std::move(a) и rvalue, в результате не создаётся временный объект. Эта проблема вынудила комитет ввести третью категорию value. Это что то, что может быть связано с rvalue ссылкой, хотя оно и не rvalue в традиционном понимании, и назвали это xvalue (eXpiring value). А традиционное rvalue было переименовано в prvalue(Pure rvalues).


Оба prvalue и xvalue являются rvalues. Xvalue и lvalue оба являются glvalues (Generalized lvalues). Взаимотношение между ними проще всего можно представить на диаграмме:

        expressions
          /     \
         /       \
        /         \
    glvalues   rvalues
      /  \       /  \
     /    \     /    \
    /      \   /      \
lvalues   xvalues   prvalues


Заметьте, что только xvalues является нововведением; остальные появились в результате переименования и группировки.

rvalues из C++98 в C++11 известны как prvalues. Мысленно замените все "rvalue" из предыдущих параграфов на "prvalue".


Перемещение из функций

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

unique_ptr<Shape> make_triangle()
{
    return unique_ptr<Shape>(new Triangle);
}          \-----------------------------/
                  |
                  | временный объект перемещается в c
                  |
                  v
unique_ptr<Shape> c(make_triangle());


Возможно это покажется странным, автоматические объекты (локальные переменные, которые не были объявлены как static) так же могут быть перемещены из функций:
unique_ptr<Shape> make_square()
{
    unique_ptr<Shape> result(new Square);
    return result;   // std::move не используем
}
}


Как так получилось что конструктор перемещения принимает lvalue в качестве аргумента? Область видимости переменной result заканчивается и она должна будет уничтожен во время разворачивания стека. Когда управление возвращается в место вызова переменной result больше не существует. По этой причине С++11 имеет специальное правило, которое позволяет возвращать автоматические объекты из функций без вызова std::move. Вообще вы никогда не должны использовать std::move для перемещения автоматических объектов из функций, так как это препятствует оптимизации NRVO "named return value optimization"

Никогда не используйте std::move, чтобы переместить из функции.


Обратите внимание, что в обоих фабричных функциях возвращаемый тип это значение(value), не ссылка на rvalue. Rvalue ссылки — всё ещё остаются ссылками, и как обычно, вы никогда не должны возвращать ссылки на автоматические объекты. Вызывающая сторона будет иметь дело с висящими ссылками, если вы попытаетесь сделать так:

unique_ptr<Shape>&& flawed_attempt()   // НЕ ДЕЛАЙТЕ ТАК!
{
    unique_ptr<Shape> very_bad_idea(new Square);
    return std::move(very_bad_idea);   // НЕВЕРНО!
}


Никогда не возвращайте автоматические объекты по rvalue ссылке. Перемещение производится исключительно перемещающим конструктором, не вызовом std::move и не только лишь привязкой rvalue к ссылок на rvalue.


Перемещение в члены класса

Рано или поздно вы попытаетесь написать код навроде этого:
class Foo
{
    unique_ptr<Shape> member;

public:

    Foo(unique_ptr<Shape>&& parameter)
    : member(parameter)   // ошибочка
    {}
};


Обычно компилятор пожалуется на то что параметр lvalue. Если вы посмотрите на этот тип вы увидите ссылку на rvalue, но rvalue ссылка просто означает "ссылку, которая привязывается к rvalue"; Это не означает что сама ссылка является rvalue! В самом деле parameter это просто обычная переменная с именем. Вы можете использовать parameter столько раз, сколько вам нужно внутри тела конструктора, и это всегда будет относится к одному и тому же объекту. Неявное перемещение из него будет опасным, по этому оно запрещено языком.

Именованная rvalue ссылка является lvalue, как и любая другая переменная.


Решение в том, чтобы вручную разрешить перемещение:
class Foo
{
    unique_ptr<Shape> member;

public:

    Foo(unique_ptr<Shape>&& parameter)
    : member(std::move(parameter))   // обратите внимание на std::move
    {}
};


Вы можете возразить, что parameter больше не используется после инициализации члена. Почему тут нет специального правила пропускать вставку std::move как было с возвращаемым значением? Возможно потому, что это было бы слишком сложно для реализации компилятора. Например сто если тело конструктора в другой единице трансляции? В отличие от этого в возвращаемом значении гораздо проще по таблице символов определить есть ли идетнификаторы после оператора return, относящиеся к автоматическому объекту.

Вы также можете передать параметр по значению. Для move-only типов, таких как unique_ptr похоже пока не существует устоявшейся идиомы. Я предпочитаю передавать по значению, так как уменьшает количество путаницы в интерфейсе.

Специальные функции-члены

C++98 неявно определяет три специальных функции-члена: конструктор копирования, оператор присваивания и деструктор.
X::X(const X&);              // конструктор копирования
X& X::operator=(const X&);   // копирующий оператор присваивания 
X::~X();                     // деструктор



Как мы знаем rvalue ссылки прошли через нескольких версий. С версии 3.0 C++11 добавляет две дополнительных специальных функции-члена: конструктор перемещения и перемещающий оператор присваивания. Заметьте, что ни VC10 ни VC11 пока не поддерживают 3.0, поэтому мы будем реализовывать их самостоятельно.

X::X(X&&); // конструктор перемещения
X& X::operator=(X&&); // перемещающий оператор присваивания

эти две специальные функции объявляются неявно только если они не объявлены вручную. И ещё если вы определили свои собственные перемещающие конструктор или оператор присваивания неявные копирующие конструктор и оператор присваивания не объявляются.

Что эти правила означают на практике?

Если вы напишете класс без ресурсов, которыми нужно управлять, тогда нет необходимости в какой либо из пяти специальных функций, и у вас будет корректная семантика копирования и перемещения без вашего вмешательства. Иначе вам нужно реализовывать спецфункции самостоятельно. И конечно же если ваш класс не получает преимуществ от семантики перемещения, то нет необходимости в реализации специальных операций перемещения.

Заметьте, что копирующий оператор присваивания и перемещающий оператор присваивания могут быть объединены в один унифицированный оператор присваивания, принимающий аргумент по значению:

X& X::operator=(X source)    // унифицированный оператор присваивания
{
    swap(source);           
    return *this;
}


Таким образом число спецфункций уменьшается до пяти.

Универсальные ссылки


Посмотрите на следующую шаблонную функцию:

template<typename T>
void foo(T&&);


Вы можете ожидать что T&& привязывается только к rvalues, потому, что на первый взгляд это выглядит как ссылка на rvalue. Как оказывается T&& также связывается с lvalue

foo(make_triangle());   // T является unique_ptr<Shape>, T&& является unique_ptr<Shape>&&
unique_ptr<Shape> a(new Triangle);
foo(a);                 // T является unique_ptr<Shape>&, T&& является unique_ptr<Shape>&


Если аргумент это rvalue типа X, T становится типом X, и тут T&& означает X&&. Это ожидаемо. Но если аргумент lvalue типа X, благодаря специальному правилу T становится типом X&, отсюда T&& будет означать что то вроде X& &&. Но так как ссылок на ссылки в C++ нет тип X& && сокращается до X&

По началу это может звучать сбивающим с толку, такое сокращение ссылок предназначено для обеспечения возможности идеальной передачи(perfect forwarding)

T&& это не rvalue ссылка, а универсальная ссылка. Она также привязывается к lvalue, в этом случае T и T&& оба ссылки на lvalue.



Реализация перемещения

Теперь, когда вы понимаете сокращение ссылок (reference collapsing), посмотрим как реализована std::move


template<typename T>
typename std::remove_reference<T>::type&&
move(T&& t)
{
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

Как вы видите move принимает параметр любого типа, благодаря универсальной ссылке T&& и возвращает ссылку на rvalue. Вызов мета-функции std::remove_reference<T>::type необходим, иначе для lvalue типа X, возвращаемый тип будет X& &&, который сократится до X&. Так как это всегда lvalue (вспомните, что именованная rvalue ссылка является lvalue) но мы хотим привязать t к ссылке на rvalue, мы явно приводим t к корректному возвращаемому типу. Вызов функции, возвращающей ссылку на rvalue сам по себе является xvalue.

Вызов функции, возвращающей ссылку на rvalue такой, как td::move является xvalue.

Отредактировано 26.02.2015 15:16 cthsq . Предыдущая версия . Еще …
Отредактировано 26.02.2015 13:57 cthsq . Предыдущая версия .
Re[2]: коротко о мув семантике
От: LaptevVV Россия  
Дата: 28.08.14 13:58
Оценка: -1
Здравствуйте, cthsq, Вы писали:

C>перепечатано из

C>http://stackoverflow.com/questions/3106110/what-are-move-semantics


C>Походу самый простой способ понять move семантику — это на примере кода. Давайте начнём с очень простого класса строк, который всего лишь хранит указатель на размещённый в куче блок памяти:

Вот что интересно.
Мне не нужно языкового механизма, чтобы реализовать семантику перемещения в классе, управляющем памятью.
Собственно, МастерЗив тут уже написал об этом.
Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: коротко о мув семантике
От: Tilir Россия http://tilir.livejournal.com
Дата: 28.08.14 14:39
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?


Чтобы разнести механизмы. Вам знакома страшная (уже не страшная) идиома COAP (container of autoptr)? Фишка была в том, что никакой возможности различить что же происходит, copy или move было нельзя. В этом плане unique_ptr безопасен именно в связи с тем, что появился механизм rvalue-ссылок на уровне языка


std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; /* мамо, чому я зипсував p? */


но

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p); /* тю! так це ж перемищення! */


и что особенно важно, вот так уже нельзя:

std::unique_ptr<int> p2 = p; /* gang-bang (!) */


То есть какой-нибудь std::vector внутри себя попытавшись скопировать такой объект отвалится на этапе компиляции, а не породит рандомное поведение при исполнении.

Минус полшанса острелить себе ногу.

А потом успевающим студентам можно задать на дом вопросы:
1) Почему нельзя безопасно сделать autoptr of array типа std::auto_ptr<int*> p(new int[10])?
2) Как rvalue refs помогают сделать unique_ptr of array безопасным?
Re[3]: Пример по семантике переноса
От: c-smile Канада http://terrainformatica.com
Дата: 28.08.14 17:36
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Abyx, Вы писали:


A>>или может стоит сначала рассказать про замену копирования на swap

A>>а потом сказать что вместо вызова swap руками есть мув-семантика
LVV>Вот! Кажись то, что нужно!

Да, в любом случае надо объяснять идиому swap.
А потом уже механизм move как а) обобщение swap и как б) поддержку применимости swap на уровне языка (rvalue ссылки).

Пример со сложением двух строк (какой-то простой класс string в котором string owns char vector exclusively)
string a = "abc";
string b = a;
string c = a + b;


мне кажется наиболее показательным.

Там достаточно наглядно можно показать сколько памяти требуется для выполнения этих трех строк без и c rvalue.
И почему, скажем, swap (как механизм делания move руками) в данном случае применить нельзя без введения дополнительных сущностей (типа temporary_string костылей и пр.)
На этом же примере и RVO можно, кстати, объяснить.
Re: Пример по семантике переноса
От: Шахтер Интернет  
Дата: 29.08.14 15:35
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Не могли бы наши гуру предложить простой (дубовый, кондовый... ), но в то же время точно отражающий семантику переноса пример?

LVV>Особенно обращаюсь к Кодту и Павлу Кузнецову — может быть вам уже приходилось это использовать и/или объяснять?
LVV>Буду весьма признателен.

На уровне метафор -- передали корзину с яблоками от одного владельца другому. Тогда как при копировании возникает дубль корзины.
Поэтому перенос, как правило, возможен как эффективная операция (O(1) noexcept, только переписать собственника в документах на владение), а копирование -- нет.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Пример по семантике переноса
От: Rinbe Россия  
Дата: 29.08.14 16:21
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Изучаю тут С++ для преподавания студентам.

LVV>И столкнулся с одной проблемой: не могу найти простого вменяемого примера для объяснения семантики переноса.
LVV>Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.

Я чего то не понимаю, это разве не твоя книга: C++. Экспресс курс
Автор(ы): Валерий Лаптев
Издательство: БХВ-Петербург
Цена: 172р.

Книга представляет собой руководство по программированию на C++, позволяющее быстро освоиться в данном алгоритмическом языке, и включает как необходимый теоретический материал, так и реализации задуманных программ в виде листингов, поясняющих
Re[2]: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 29.08.14 17:07
Оценка:
Здравствуйте, Rinbe, Вы писали:

R>Здравствуйте, LaptevVV, Вы писали:


LVV>>Изучаю тут С++ для преподавания студентам.

LVV>>И столкнулся с одной проблемой: не могу найти простого вменяемого примера для объяснения семантики переноса.
LVV>>Теоретически все понятно: кода мы переносим файл, то сам файл с места не сдвигается, а меняется только управляющая информация.

R>Я чего то не понимаю, это разве не твоя книга: C++. Экспресс курс
Автор(ы): Валерий Лаптев
Издательство: БХВ-Петербург
Цена: 172р.

Книга представляет собой руководство по программированию на C++, позволяющее быстро освоиться в данном алгоритмическом языке, и включает как необходимый теоретический материал, так и реализации задуманных программ в виде листингов, поясняющих

Это — моя книга. И что? У меня еще есть...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 29.08.14 17:10
Оценка:
Повторяю еще раз — на уровне метафор все понятно.
Не хватает пока конкретного ПРОСТОГО примера для показа учням.
Но вроде потихоньку вырисовывается.
Поднял еще раз Стенли Липпмана — там МНОГО места посвящено проблемам swap().
Именно то, что нужно.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: коротко о мув семантике
От: Abyx Россия  
Дата: 29.08.14 19:58
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Вот что интересно.

а мне интересно как такая простая вещь может быть интересна.
LVV>Мне не нужно языкового механизма, чтобы реализовать семантику перемещения в классе, управляющем памятью.
LVV>Собственно, МастерЗив тут уже написал об этом.
LVV>Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?
я уже не раз говорил — если надо знать зачем та или иная фича в C++1x — читайте proposal.
In Zen We Trust
Re: Как сделать перенос из свопа
От: Шахтер Интернет  
Дата: 30.08.14 11:08
Оценка: 1 (1)
Может быть поможет.


template <class T> void Swap(T &a,T &b); // уже реализована как-то

template <class T>
void MoveBySwap(T &dst,T &src) // перемещение существующих объектов
 {
  T temp{}; // объект с нулевым состоянием

  Swap(dst,src);
  Swap(src,temp);
 }

template <class T>
T * CreateMoveBySwap(void *mem,T &src) // создание нового объекта перемещением старого 
 {
  T *ret=new(mem) T{};

  Swap(*ret,src);

  return ret;
 }
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Как сделать перенос из свопа
От: LaptevVV Россия  
Дата: 30.08.14 13:35
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Может быть поможет.

Спасибо. Именно это написано у Стенли Липпмана...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Как сделать перенос из свопа
От: Шахтер Интернет  
Дата: 30.08.14 13:45
Оценка: +1 :))
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Шахтер, Вы писали:


Ш>>Может быть поможет.

LVV>Спасибо. Именно это написано у Стенли Липпмана...

Нуу, правильные мысли не только мне в голову приходят...
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Пример по семантике переноса
От: lxa http://aliakseis.livejournal.com
Дата: 31.08.14 12:59
Оценка: 20 (1)
Move Semantics in C++11, Part 1: A New Way of Thinking About Objects
Move Semantics in C++11, Part 2: Design and Implementation of Special Move Functions
Re[4]: коротко о мув семантике
От: jazzer Россия Skype: enerjazzer
Дата: 01.09.14 10:33
Оценка:
Здравствуйте, Abyx, Вы писали:

A>я уже не раз говорил — если надо знать зачем та или иная фича в C++1x — читайте proposal.


+1. Там всегда есть секция "А нафига"
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Пример по семантике переноса
От: lxa http://aliakseis.livejournal.com
Дата: 02.09.14 09:24
Оценка:
Ещё пара интересных ссылок:
Andrei Alexandrescu: Generic&lt;Programming&gt;: Move Constructors
chromium / chromium/src/base / master / . / move.h
Re[3]: коротко о мув семантике
От: Erop Россия  
Дата: 02.09.14 22:41
Оценка: 1 (1)
Здравствуйте, LaptevVV, Вы писали:

LVV>Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?


Что бы скомпенсировать ошибку дизайна STL...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Пример по семантике переноса
От: LaptevVV Россия  
Дата: 11.09.14 03:00
Оценка:
Сообразил, как рассказывать студентам.
1. Надо делать класс-контейнер, в котором требуется перегрузить конструктор копирования и операцию присваивания.
И обычным образом объяснить семантику значений. Ну, что-то вроде реализации вектора или дека основе динамического массива.
2. Потом возникает вопрос: а если элементами этого контейнера будут такие объекты, которые сами используют динамическую память?
Например, строки — контейнер символом в динамическом массиве.
Показать, что в семантике копирования дофига получается лишней работы по созданию-копированию-уничтожению временных объектов.
3. Показываем решение — просто переприсвоить поля-указатели.
Сами элементы не копировались-дублировались, а только необходимые управляющие поля.
Вот оно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Пример по семантике переноса
От: jazzer Россия Skype: enerjazzer
Дата: 11.09.14 03:17
Оценка: +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Сообразил, как рассказывать студентам.

LVV>1. Надо делать класс-контейнер, в котором требуется перегрузить конструктор копирования и операцию присваивания.
LVV>И обычным образом объяснить семантику значений. Ну, что-то вроде реализации вектора или дека основе динамического массива.
LVV>2. Потом возникает вопрос: а если элементами этого контейнера будут такие объекты, которые сами используют динамическую память?
LVV>Например, строки — контейнер символом в динамическом массиве.
LVV>Показать, что в семантике копирования дофига получается лишней работы по созданию-копированию-уничтожению временных объектов.
LVV>3. Показываем решение — просто переприсвоить поля-указатели.
LVV>Сами элементы не копировались-дублировались, а только необходимые управляющие поля.
LVV>Вот оно!

Ну то есть http://rsdn.ru/forum/cpp/5756402.1
Автор: jazzer
Дата: 26.08.14

jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: коротко о мув семантике
От: B0FEE664  
Дата: 17.09.14 13:48
Оценка: -1
Здравствуйте, Abyx, Вы писали:

LVV>>Вот что интересно.

A>а мне интересно как такая простая вещь может быть интересна.
LVV>>Мне не нужно языкового механизма, чтобы реализовать семантику перемещения в классе, управляющем памятью.
LVV>>Собственно, МастерЗив тут уже написал об этом.
LVV>>Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?
A>я уже не раз говорил — если надо знать зачем та или иная фича в C++1x — читайте proposal.

Прочита я proposal. Ну и? Мне по-прежнему не понятно, зачем нужна семантика перемещения. Вернее так: я понимаю, что с этой новой семантикой сильно сокращается необходимый объём кода. Но я так и не понял, чего нельзя сделать без её использования.

Хотите перемещать временные объекты? Ну и что этому мешает?
class RValueRefString
{
  friend class string;
  private:
    char* data;
    size_t sz;
  public:

    RValueRefString(const char* p)
    {
        sz = strlen(p) + 1;
        data = new char[sz];
        memcpy(data, p, sz);
    }

    RValueRefString(RValueRefString& r)
    {
        if ( this != &r )
        {
          delete[] data;
        
          sz = r.sz;
          data = r.data;
          r.sz = 0;
          r.data = NULL;
        }  
    }

   ~RValueRefString()
    {
        delete[] data;
    }

    RValueRefString(const string& rStr1, const string& rStr2);
};


class string
{
    friend class RValueRefString;
    char* data;

  public:

    string(const char* p)
    {
        size_t size = strlen(p) + 1;
        data = new char[size];
        memcpy(data, p, size);
    }

    ~string()
    {
        delete[] data;
    }

    string(const string& that)
    {
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        memcpy(data, that.data, size);
    }

    string(RValueRefString& r)
    {
        data = r.data;
        r.sz = 0;
        r.data = NULL;
    }

    void operator = (RValueRefString& that)
    {
        delete[] data;
    
        size_t size = that.sz;
        data = new char[size];
        memcpy(data, that.data, size);
    }
    
    const char* get() const { return data; }
};


RValueRefString::RValueRefString(const string& rStr1, const string& rStr2)
{
    size_t sz1 = strlen(rStr1.data);
    size_t sz2 = strlen(rStr2.data);
    sz   = sz1 + sz2 + 1;
    data = new char[sz];
    memcpy(data,       rStr1.data, sz1);
    memcpy(data + sz1, rStr2.data, sz2 + 1);
}


RValueRefString operator + (const string& rStr1, const string& rStr2)
{
    return RValueRefString(rStr1, rStr2);
}


int main(int argc, char * argv[])
{
  string strA("abc");
  string strB("def");
  
  string strC = strA + strB;
  
  std::cout << strC.get() << std::endl;
  std::cout << "the end" << std::endl;
  
  _getch();
  return 0;
}


Почему это сделали фичей языка, а не библиотечным методом из proposal не ясно.
И каждый день — без права на ошибку...
Re[5]: коротко о мув семантике
От: Кодт Россия  
Дата: 17.09.14 13:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Почему это сделали фичей языка, а не библиотечным методом из proposal не ясно.


Потому что задача типовая, и удваивать сущности (auto_ptr и auto_ptr_ref) в каждом таком случае — удовольствия никакого.
Опять же,
— дефолтная реализация перемещения (то есть, копирование) доступна из коробки — не надо патчить все типы подряд
— компилятор может автоматически выводить тип ссылки из основного, и основной из ссылки; в случае с библиотеками это была бы дополнительная морока
Перекуём баги на фичи!
Re[5]: коротко о мув семантике
От: saf_e  
Дата: 17.09.14 14:21
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Abyx, Вы писали:


LVV>>>Вот что интересно.

A>>а мне интересно как такая простая вещь может быть интересна.
LVV>>>Мне не нужно языкового механизма, чтобы реализовать семантику перемещения в классе, управляющем памятью.
LVV>>>Собственно, МастерЗив тут уже написал об этом.
LVV>>>Тогда возникает вопрос: зачем внесли в язык то, что реализовывалось и без оного?
A>>я уже не раз говорил — если надо знать зачем та или иная фича в C++1x — читайте proposal.

BFE>Прочита я proposal. Ну и? Мне по-прежнему не понятно, зачем нужна семантика перемещения. Вернее так: я понимаю, что с этой новой семантикой сильно сокращается необходимый объём кода. Но я так и не понял, чего нельзя сделать без её использования.


BFE>Почему это сделали фичей языка, а не библиотечным методом из proposal не ясно.


В вашем случае нельзя перейти от string к RValueRefString. А если это сделать получиться что-то типа shared_ptr/intrusive_ptr. Как следствие нужно внимательно жонглировать типами (не то принял/вернул потерял производительность).

Ну и теряется универсальность, вы не смоежете написать универсальный std::swap.

Опять-таки не слова о perfect-forwarding.
Re[6]: коротко о мув семантике
От: B0FEE664  
Дата: 17.09.14 14:39
Оценка:
Здравствуйте, Кодт, Вы писали:

BFE>>Почему это сделали фичей языка, а не библиотечным методом из proposal не ясно.

К>Потому что задача типовая, и удваивать сущности (auto_ptr и auto_ptr_ref) в каждом таком случае — удовольствия никакого.
Ну, может, в каждом и не надо, тем более, что, если я правильно понимаю, для POD типов оптимизации не предусмотрено.

К>Опять же,

К>- дефолтная реализация перемещения (то есть, копирование) доступна из коробки — не надо патчить все типы подряд
К>- компилятор может автоматически выводить тип ссылки из основного, и основной из ссылки; в случае с библиотеками это была бы дополнительная морока
Всё так. Только вот из proposal это не ясно. Там говорится про какие-то ужасы о невозможности:

1. One of the most important applications for move semantics is to move from temporaries (rvalues). Copy constructor elision (NRVO) almost fixes this, but not quite. Sometimes elision is not possible. Other times even when NRVO is done, it is not sufficient: alternate algorithms are desirable when the source data is known to be an rvalue (e.g. string+string example to be discussed below).
2. Moving from const objects (even rvalues) must be prohibited. It is very difficult to distinguish between a const and an rvalue in the current language (not impossible ... auto_ptr pulls it off).




Кстати, вот такой код:
string str = str1 + str2 + str3;
можно существенно ускорить отложив операции сложения до момента присваивания, чего встроенная семантика переноса не гарантирует для длинных строк. И получается, что задача так до конца и не решена.
И каждый день — без права на ошибку...
Re[5]: коротко о мув семантике
От: Abyx Россия  
Дата: 17.09.14 14:49
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Хотите перемещать временные объекты? Ну и что этому мешает?

BFE>
BFE>какой-то говнокод
BFE>


ничего что твой говнокод невалиден?
ты не можешь делать l-value референс на временный объект

судя по _getch ты используешь VC++, и значит ты там говоришь
"зачем в С++11 расширили стандарт С++03, если можно сделать то же самое на С++03, но только с расширениями стандарта С++03"?

я уже вроде писал выше, что тут вся суть в добавлении новых категорий выражений, которые позволяют безопасно биндить временные объекты к мутабельным ссылкам,
казалось бы простая штука — и всеравно люди не понимают. как так?
In Zen We Trust
Re[6]: коротко о мув семантике
От: B0FEE664  
Дата: 17.09.14 15:09
Оценка:
Здравствуйте, saf_e, Вы писали:

BFE>>Прочита я proposal. Ну и? Мне по-прежнему не понятно, зачем нужна семантика перемещения. Вернее так: я понимаю, что с этой новой семантикой сильно сокращается необходимый объём кода. Но я так и не понял, чего нельзя сделать без её использования.


_>В вашем случае нельзя перейти от string к RValueRefString. А если это сделать получиться что-то типа shared_ptr/intrusive_ptr.

Не обязательно. Можно написать аналог std::move. Дело не хитрое:
RValueRefString string::MoveToRValueRefString()
{
    RValueRefString ref;
    
    ref.data = data;
    ref.sz   = strlen(data) + 1;
    data     = NULL;
    
    return ref;
}



_>Как следствие нужно внимательно жонглировать типами (не то принял/вернул потерял производительность).


Так и с новой семантикой перемещения дела обстоят точно так же, забыл добавить оператор:
string&& operator+(string&& x, const string& y)
{
    return x += y;
}

потерял в производительности.

_>Ну и теряется универсальность, вы не смоежете написать универсальный std::swap.

Конечно нет. Я этого и не утверждал.

_>Опять-таки не слова о perfect-forwarding.

Но ведь perfect-forwarding — не главная причина введения семантики перемещения?
И каждый день — без права на ошибку...
Re[7]: коротко о мув семантике
От: Кодт Россия  
Дата: 17.09.14 15:10
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Кстати, вот такой код:

BFE>string str = str1 + str2 + str3;
BFE>можно существенно ускорить отложив операции сложения до момента присваивания, чего встроенная семантика переноса не гарантирует для длинных строк. И получается, что задача так до конца и не решена.

Этак мы до хаскелла и идриса доберёмся, с их формальными преобразованиями программ.

Существенное ускорение там можно сделать в три этапа:
— приведение к acc += str1; acc += str2; acc += str3; str = move(acc);
— приведение к len = str1.size()+str2.size()+str3.size(); acc.reserve(len); ...
— полная ленивость: если нет str =, то остаться в виде expression template
Перекуём баги на фичи!
Re[7]: коротко о мув семантике
От: saf_e  
Дата: 17.09.14 15:13
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, saf_e, Вы писали:


BFE>>>Прочита я proposal. Ну и? Мне по-прежнему не понятно, зачем нужна семантика перемещения. Вернее так: я понимаю, что с этой новой семантикой сильно сокращается необходимый объём кода. Но я так и не понял, чего нельзя сделать без её использования.


_>>Как следствие нужно внимательно жонглировать типами (не то принял/вернул потерял производительность).


BFE>Так и с новой семантикой перемещения дела обстоят точно так же, забыл добавить оператор:

BFE>
BFE>string&& operator+(string&& x, const string& y)
BFE>{
BFE>    return x += y;
BFE>}
BFE>

BFE>потерял в производительности.

Ну, тип становится всего один, и при возврате не нужно писать &&

_>>Ну и теряется универсальность, вы не смоежете написать универсальный std::swap.

BFE>Конечно нет. Я этого и не утверждал.

_>>Опять-таки не слова о perfect-forwarding.

BFE>Но ведь perfect-forwarding — не главная причина введения семантики перемещения?

Ну, собственно, к чему веду и я и все остальные. Фича нужная и позволяет меньшими усилиями писать производительный код там, где раньше это было или тяжело или невозможно.
Re[6]: коротко о мув семантике
От: B0FEE664  
Дата: 17.09.14 15:32
Оценка:
Здравствуйте, Abyx, Вы писали:

BFE>>Хотите перемещать временные объекты? Ну и что этому мешает?

BFE>>
BFE>>какой-то говнокод
BFE>>

A>ничего что твой говнокод невалиден?
Где?

A>ты не можешь делать l-value референс на временный объект

И какое отношение это имеет к коду?

A>судя по _getch ты используешь VC++, и значит ты там говоришь

я много чего использую.

A>"зачем в С++11 расширили стандарт С++03, если можно сделать то же самое на С++03, но только с расширениями стандарта С++03"?

Нет. Я говорю, что отсыл на proposal не является ответом на вопрос Лаптева.

A>я уже вроде писал выше, что тут вся суть в добавлении новых категорий выражений, которые позволяют безопасно биндить временные объекты к мутабельным ссылкам,

Т.е. всё сводится к удобству и безопасности, а ни о какой новой функциональности речи не идёт?

A>казалось бы простая штука — и всеравно люди не понимают. как так?

Чего именно я не понимаю?
И каждый день — без права на ошибку...
Re[8]: коротко о мув семантике
От: B0FEE664  
Дата: 17.09.14 15:43
Оценка:
Здравствуйте, saf_e, Вы писали:

BFE>>>>Прочита я proposal. Ну и? Мне по-прежнему не понятно, зачем нужна семантика перемещения. Вернее так: я понимаю, что с этой новой семантикой сильно сокращается необходимый объём кода. Но я так и не понял, чего нельзя сделать без её использования.


_>>>Как следствие нужно внимательно жонглировать типами (не то принял/вернул потерял производительность).

BFE>>Так и с новой семантикой перемещения дела обстоят точно так же, забыл добавить оператор:
BFE>>
BFE>>string&& operator+(string&& x, const string& y)
BFE>>{
BFE>>    return x += y;
BFE>>}
BFE>>

BFE>>потерял в производительности.
_>Ну, тип становится всего один, и при возврате не нужно писать &&
В данном операторе наличие && у возвращаемого типа обеспечивает рост производительности
И каждый день — без права на ошибку...
Re[7]: коротко о мув семантике
От: Abyx Россия  
Дата: 17.09.14 16:54
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Abyx, Вы писали:


BFE>>>Хотите перемещать временные объекты? Ну и что этому мешает?

BFE>>>
BFE>>>какой-то говнокод
BFE>>>

A>>ничего что твой говнокод невалиден?
BFE>Где?
в компиляторе. твой код не компилируется.

A>>ты не можешь делать l-value референс на временный объект

BFE>И какое отношение это имеет к коду?
да, у тебя временный объект (результат op+) передается в конструктор RValueRefString(RValueRefString& r)
это не валидный С++, и компилируется только за счет расширений VC++

A>>я уже вроде писал выше, что тут вся суть в добавлении новых категорий выражений, которые позволяют безопасно биндить временные объекты к мутабельным ссылкам,

BFE>Т.е. всё сводится к удобству и безопасности, а ни о какой новой функциональности речи не идёт?
давай ты сначала напишешь свой код так чтобы он компилировался строго согласно С++03, а потом обсудим это еще раз.
рекомендую этот онлайн-компилятор — http://coliru.stacked-crooked.com/a/30fcce2f2edbf1cb
In Zen We Trust
Re[2]: Пример по семантике переноса
От: Erop Россия  
Дата: 17.09.14 18:26
Оценка: 1 (1) +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Вот оно!


Всё круче! Можно, например, сделать массив потоков, пооткрывать их все прямо внутри массива, а потом массив заресайзить...
То есть можно двигать вообще некопируемые в принципе объекты,..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Пример по семантике переноса
От: vpchelko  
Дата: 17.09.14 21:30
Оценка:
Здравствуйте, LaptevVV, Вы писали:

Опять мешаете перенос, копирование и присваивание. Каша. Опять же вижу выше по ссылкам, где "move" называют присваивание с копированием
int m=7, n=0;
n=m; //"move" m to n.

... плохой пример, мешает пониманию.
Сало Украине, Героям Сала
Отредактировано 17.09.2014 21:58 vpchelko . Предыдущая версия . Еще …
Отредактировано 17.09.2014 21:56 vpchelko . Предыдущая версия .
Отредактировано 17.09.2014 21:49 vpchelko . Предыдущая версия .
Отредактировано 17.09.2014 21:45 vpchelko . Предыдущая версия .
Отредактировано 17.09.2014 21:31 vpchelko . Предыдущая версия .
Re[8]: коротко о мув семантике
От: B0FEE664  
Дата: 18.09.14 10:56
Оценка:
Здравствуйте, Abyx, Вы писали:

A>>>ты не можешь делать l-value референс на временный объект

BFE>>И какое отношение это имеет к коду?
A>да, у тебя временный объект (результат op+) передается в конструктор RValueRefString(RValueRefString& r)
A>это не валидный С++, и компилируется только за счет расширений VC++

О! Теперь я понял о чём речь. Я всё время забываю, что в стандарте есть этот прямой запрет.
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.