Re: Зачем нужно копирование/перемещение
От: uncommon Ниоткуда  
Дата: 11.08.17 17:42
Оценка:
Здравствуйте, MTD, Вы писали:

MTD>Я преподаю С++ студентам пару лет и неизменно вижу круглые непонимающие глаза когда я рассказываю о копировании, о том, что тут передача по значению, тут по ссылке, а тут вообще по константной ссылке. Когда же после этого речь заходит про перемещение, то у части эмоционально нестойких начинается нервный тик. Итак мои тезисы: копирование и перемещение неоправданно сложны, не интуитивны, приводят к снижению быстродействия и ошибкам. Передача объектов по ссылке на объект всегда достаточна.


Может ты пытаешься втолкнуть всё сразу, отчего и происходит непонимание у студентов?

Копирование — это проще простого, понятно на интуитивном уровне, и не должно вызывать никаких проблем. В C++ все value типы не только поддерживают копирование, но и делают это одинаковым образом. Т.е. std::vector можно скопировать точно так же как и int без каких-либо специфичных для вектора особенностей. На начальном уровне достаточно просто ограничиться копированием без ссылок и перемещений: объявлять все переменные по значению, передавать все параметры по значению, всегда возвращать по значению, и т.д.

Сложные типы тоже работают с копированием без проблем или лишних телодвижений:
class student {
  int id_;
  std::string name_;

public:
  student(int id, std::string name)
    : id_{id}
    , name_{name}
  {}

  // copy-constructor по-умолчанию

  int id() const { return id_; }
  std::string name() const { return name_; }
};

student vasya;
student petya = vasya;                // точная копия
assert(petya.name() == vasya.name()); // работает как и ожидается


То, что копирование неоптимально, на начальном этапе совершенно неважно. Гораздо более важно понимание основных принципов программирования.

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

А перемещений вообще в языке не было до C++11. Это чистого рода оптимизация, которую можно оставить для продвинутых студентов.
Re[8]: Зачем нужно копирование/перемещение
От: alex_public  
Дата: 11.08.17 19:28
Оценка:
Здравствуйте, MTD, Вы писали:

_>>Ну идея описана верно, но реализация весьма далека от реальности

MTD>Пример должен быть простым и иллюстрировать идею, пытаться в двух предложениях описать все мироустройство обречено на провал. Вот ты, например, не поленился и накопипастил кода — усердие достойное похвалы, но для новичка код сложный, а для тем кто в теме и так все понятно.

Всё верно, но при условии что упрощение не нарушает базовых принципов. А твой пример их нарушал — буфер SSO существует сам по себе (и своим существованием увеличивает размер экземпляра класса string), а не только как union с указателем.

_>>неужели преподаватель C++ никогда не заглядывал в исходники стандартной библиотеки? )

MTD>Ох, ребята, я с вас умиляюсь, вы все про меня лучше меня знаете: и куда я заглядывал, и что я знаю, и сколько у меня опыта, и нужно ли мне преподавать. Впрочем если вам это помогает справиться с какими-то личностными проблемами — вперед, мне не жалко.

Ну это ты на самом деле сам подставился как раз информацией о том, что являешься преподавателем C++ у студентов. Если бы просто какой-то программист на форуме начал подобное обсуждение и при этом допустил бы пару мелких косяков, то скорее всего никто и не обратил бы внимания (ну мало ли, неопытный коллега, в этом нет ничего страшного), сосредоточившись на теме обсуждения. А вот преподавателю всегда все косяки отметят, потому как он априори не должен их допускать. )))
Re[9]: Зачем нужно копирование/перемещение
От: MTD https://github.com/mtrempoltsev
Дата: 11.08.17 19:43
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А твой пример их нарушал — буфер SSO существует сам по себе (и своим существованием увеличивает размер экземпляра класса string), а не только как union с указателем.


Что-то я не помню в стандарте таких требований к реализации.

_>А вот преподавателю всегда все косяки отметят, потому как он априори не должен их допускать. )))


Да, так должно быть и я к этому стремлюсь. Спасибо, коллеги, помогаете разобраться в некоторых вещах!
Re[4]: Зачем нужно копирование/перемещение
От: Meyers  
Дата: 11.08.17 23:25
Оценка:
_>>>В частность операция перемещения это просто желание убрать лишние операции при передаче результата.
MTD>>Это понятно и на это студенты резонно замечают, что не было бы копирования не надо было бы и костылей в виде перемещения.
LVV>Сравните С++ и C# (или Java) в своих лекциях.
LVV>Копирование — это не костыли, а один из вариантов семантики.
LVV>В C# тоже ж добавили костылей — value class (классы-значения).
LVV>B метод clone() — это такой же костыль для реализации копирования в языке, где перемещение — основная семакнтика.

C++ провозглашает принцип "не платишь за то, что явно не используешь" и неявное копирование этому противоречит. А вот метод clone() — полностью подходит под данный принцип.
Re[3]: Зачем нужно копирование/перемещение
От: Vain Россия google.ru
Дата: 11.08.17 23:32
Оценка:
Здравствуйте, MTD, Вы писали:

V>>С++ вообще неоправданно сложен не интуитивен. Вот бургеры переворачивать в МакДональдспе — просто и интуитивно.

MTD>Печально, что вместо конструктивного обсуждения, интеллекта хватило только для перехода на личности.
Ну ты ж переходишь на личности (1
Автор: MTD
Дата: 05.08.17
, 2
Автор: MTD
Дата: 08.08.17
), а ему нельзя?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: Зачем нужно копирование/перемещение
От: N. I.  
Дата: 12.08.17 08:18
Оценка:
Meyers:

M>C++ провозглашает принцип "не платишь за то, что явно не используешь" и неявное копирование этому противоречит.


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

M>А вот метод clone() — полностью подходит под данный принцип.


Хорошо, предположим, что от более высокоуровневой абстракции "инициализация объекта" (потенциально имеющей своей составной частью вызов конструктора копирования) мы перешли к менее высокоуровневой абстракции "прямой вызов функции копирования для инициализации объекта". И что мы с этого поимеем? От этого наша программа сразу станет работать быстрее? Эта clone, поди, тоже "неявно" кучу операций может делать — пока под её капот не заглянешь, не узнаешь, чем она там занимается. А вдруг она неэффективная и в данном конкретном месте копирование можно было бы реализовать лучше? А ну-ка, давайте и её расщепим на атомы, и вставим все её потроха по месту копирования, шоб все действия перед глазами были.
Re[5]: Зачем нужно копирование/перемещение
От: LaptevVV Россия  
Дата: 12.08.17 15:54
Оценка:
M>C++ провозглашает принцип "не платишь за то, что явно не используешь" и неявное копирование этому противоречит. А вот метод clone() — полностью подходит под данный принцип.
1. Тогда претензии — к Си. Семантика копирования взята оттуда.
2. Неявное копирование ссылок в С# или Java — не лучше.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[6]: Зачем нужно копирование/перемещение
От: Meyers  
Дата: 12.08.17 17:39
Оценка:
TL;DR.
Re[6]: Зачем нужно копирование/перемещение
От: Meyers  
Дата: 12.08.17 18:24
Оценка:
LVV>2. Неявное копирование ссылок в С# или Java — не лучше.

В мантре C++ акцент стоит на "не платишь". Неявное копирование ссылок одинаково дёшево (можно даже сказать бесплатно) для всех типов.

Так что если и выбирать какое-то поведение по-умолчанию, то, исходя из мантры C++, нужно выбрать самое дешёвое. Но в C++ выбрано самое дорогое.
Отредактировано 12.08.2017 19:34 Meyers . Предыдущая версия . Еще …
Отредактировано 12.08.2017 18:46 Meyers . Предыдущая версия .
Re: Зачем нужно копирование/перемещение
От: rm822 Россия  
Дата: 12.08.17 22:41
Оценка:
Здравствуйте, MTD, Вы писали:

MTD> копирование и перемещение неоправданно сложны

хм. а в чем именно сложность? operator= и .ctor генерируются по умолчанию, если ты не работаешь напрямую с памятью
MyType(MyType&&) = default; тоже никакой сложности не добавляют

MTD> не интуитивны, приводят к снижению быстродействия и ошибкам

для студентов — возможно, но это верно для любой технологии. Ты же не даешь детям циркулярную пилу.

MTD> Передача объектов по ссылке на объект всегда достаточна

по указателю,
Да, достаточна, но это приводит к пакостям, которые демонстрирует .net/java

Пример 1.
упрощенно
class std::string 
{
    int   m_len;
    char  smallbuffer[16];
    char* m_largebuffer;

    const char* c_str() const { retunr m_len <16 ? smallbuffer : largebuffer; }
};

побайтовое копирование для нее не работает, поэтому чтобы успешно запихивать ее в контейнер есть 2 варианта
а) move || copy, чтобы можно было на стеке создать
б) всегда создавать ее только в хипе.
Для плюсов это дурацкая затея из-за ликов и жуть как медленно
конечно Java/.net идут 3м вариантом, запрещают голые указатели, но в плюсах такое нельзя

Пример 2.
Параллелизм
Дотнетчики обожают код типа такого
class SomeContext
{
   List<...> _lazyProp;
   ... тут еще квадрилион полей
   bool IsOK(Object^ o)
   {
      if (_lazyProp == null)
          _lazyProp = InitProp();
       ......
   }
}}



а потом берем и пытаемся сделать
  SomeContext myCtx = ....
  someCollection.AsParallel().Where( x=> myCtx.IsOK(x))

и грандиозно обламываемся c thread_local myCtx , потому что копирование у них не принято, а SomeContext — тянет за собой иерархию из 50 классов, из которых копироваться умеют 2

Пример 3.
Классы задач с undo/redo
— транзакцонность
— откат состояния объекта после исключения
— lock-free и MVCC-контейнеры
— undo|redo в редакторах
все это реализуется в разы проще, если есть копирование


MTD> Обоснуйте почему копирование и перемещение это не WTF, а классно, чтобы я смог студенту обосновать, что все сделано правильно.

все сделано правильно, но студентам еще рано об этом знать, это инструмент для больших дядей экскаваторщиков, а они пока ямки под саженцы учатся копать
Re: Зачем нужно копирование/перемещение
От: Кодт Россия  
Дата: 16.08.17 10:20
Оценка: 13 (3)
Здравствуйте, MTD, Вы писали:

MTD>Передача объектов по ссылке на объект всегда достаточна.


Нет, по двум причинам, которые являются киллер-фичами языка:
1) Ломается ABI, поскольку ещё в Си можно передавать даже структуры — как по значению, так и по указателю.
2) Ломается возможность оптимизации.

Вот смотри: если ты передаёшь в функцию нечто по ссылке или указателю, то
— вынужден приземлить этот объект в адресуемую память
— адрес сам занимает память, — для мелких объектов это соизмеримо с их собственными размерами
— вызываемая сторона не может быть уверена в уникальности адреса аргумента и в неизменности состояния объекта
const X* z;
void f(const X& x, const X& y) {
  if (&x == &y) { zombie_code(); }
  if (&x == z) { zombie_code(); }
  X t = x;
  foo();
  if (t != x) { zombie_code(); }  // нет гарантии, что никто не поменял состояние объекта x извне
}
void g(X x, X y) {
  if (&x == &y) { can_be_elided(); }
  if (&x == z) { can_be_elided(); }
  X t = x;
  foo();
  if (t != x) { can_be_elided(); } // невозможно поменять локальную переменную, если её адрес не отдали наружу
}


MTD>1. Получить копию. Но явное лучше неявного, поэтому метод clone гораздо лучше. Да, уже не напишешь bigint или комплексное число с которым удобно работать как с примитивными типами, но почему эти типы просто не сделать частью языка?


Таких типов слишком дофига, чтобы делать их частью языка.

Если тебе нужен тип с семантикой значения, берёшь и почти ничего не делаешь.
Если нужен тип БЕЗ семантики значения, берёшь и отламываешь.

MTD>2. Умные указатели. Должны быть частью языка и все будет ок.


Они и есть часть языка — std::unique_ptr и std::shared_ptr.
Только смысл у всех трёх указателей — голых и двух умных — несколько разный.
Можно, конечно, придумать синтаксический сахар (как управляемые указатели в C++/CLI — с крышечкой). Но это избыточно.

MTD>Обоснуйте почему копирование и перемещение это не WTF, а классно, чтобы я смог студенту обосновать, что все сделано правильно.


Чтобы обосновать, надо начать с другого конца. А именно, с основ ООП, где проводится черта между уникальными и неуникальными данными.
С++ поддерживает обе семантики — и объекта, и значения.
В отличие от C#, где объекты отдельно, значения (структуры и примитивные типы) отдельно.

Ну а дальше начинаются вопросы: как эффективно реализовать семантику значения в разных условиях.
— когда данные легковесные или тяжеловесные
— когда явно нужно клонировать, а когда можно и сократить
— когда компилятор сам догадается, что можно сократить (все случаи copy elision, RVO, NRVO), а когда ему нужно подсказывать (std::move, например), а когда и реально приложить усилия (расшарить внутренние данные, реализовать copy on write)
Перекуём баги на фичи!
Отредактировано 17.08.2017 10:20 Кодт . Предыдущая версия .
Re[2]: Зачем нужно копирование/перемещение
От: Meyers  
Дата: 21.08.17 06:06
Оценка: -1
К> в Си можно передавать даже структуры — как по значению, так и по указателю.

Никакой "передачи по указателю" не существует. Есть взятие адреса и передача этого адреса по значению. Так что в Си есть только передача по значению.
Re[3]: Зачем нужно копирование/перемещение
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.08.17 11:52
Оценка: +1
Здравствуйте, Meyers, Вы писали:

К>> в Си можно передавать даже структуры — как по значению, так и по указателю.


M>Никакой "передачи по указателю" не существует. Есть взятие адреса и передача этого адреса по значению. Так что в Си есть только передача по значению.


Ну, во-первых, есть случай возврата большой структуры — который в подавляющем большинстве ABI реализуется как передача указателя вызывающей функцией скрытым параметром, а для программиста это возврат по значению.
Во-вторых, даже если б формально Вы были правы, по сути это бессмысленно — указатель в >99.99% не самоцель, а метод передачи того, на что он указывает.
The God is real, unless declared integer.
Re[3]: Зачем нужно копирование/перемещение
От: Vamp Россия  
Дата: 21.08.17 12:57
Оценка: +1
M>Никакой "передачи по указателю" не существует. Есть взятие адреса и передача этого адреса по значению. Так что в Си есть только передача по значению.

Бессмысленное резонерство.
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Зачем нужно копирование/перемещение
От: AlexGin Беларусь  
Дата: 28.08.17 10:35
Оценка: +1 :)
Здравствуйте, MTD, Вы писали:

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


MTD>>>Я преподаю С++ студентам пару лет....

T>>первым языком?

MTD>Нет, они уже как правило много чего еще знают, поэтому и недоумевают зачем в С++ так сделано.



Точнее: они много чего еще НЕ знают, поэтому и недоумевают зачем в С++ так сделано.

Вот насчёт конструктора копии:
1) http://www.cyberforum.ru/cpp-beginners/thread881941.html
2) http://en.cppreference.com/w/cpp/language/copy_constructor
3) http://www.geeksforgeeks.org/copy-constructor-in-cpp

Основная идея конструктора копии — сделать полноценную копию объекта,
которая не зависит от исходного объекта (её можно изменять, не затрагивая исходный объект).
Для этого выделяется память и содержимое исходного объекта копируюется на новое место.

Полезная ссылка по конструкторам перемещения и копирования:
http://www.cplusplus.com/forum/beginner/190004

На русском:
https://ru.stackoverflow.com/questions/490753/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D0%BE%D1%80-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D1%89%D0%B5%D0%BD%D0%B8%D1%8F

Вот и на хабре:
https://habrahabr.ru/post/174019
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.