Здравствуйте, rg45, Вы писали:
R>1) Обязывает предоставлять дефолтный конструктор, что не всегда приемлемо; R>3) Содержит оверхед на создание никому ненужного состояния объекта;
А чем плох конструктор по умолчанию? На мой взгляд плох не такой конструктор, а то, что нужно поддерживать в классе некое выделенное "значение по умолчанию".
Ну так move-конструктор тоже требует поддержать такое значение же?
В этом смысле я вообще не вижу разницы в подходах.
Но если говорить о попытках выпрямить невозможность перемещения содержимого вектора, то плюс такой, что вообще не надо менять язык.
Но если таки менять, то если бы как-то разрешили описывать конструкции вроде RVO, например, то есть я бы сам мог написать функцию, которой можно было бы передать буфер для конструирования там результата, и её потом было бы удобно вызывать, то ты бы мог написать так, как тебе нравится и не вводя конструктор перемещения.
Да, для конструктора перемещения надо ещё, обычно, и парный метод присваивания, кстати. И в месте вызова всегда трудно понять перемещение будет вызвано или копирование.
R>2) Вводит необоснованные ограничения на использование ссылок и констант в качестве членов классов;
Ну это я согласен. В этом месте конструктор перемещения лучше, но оператор присваивания тогда тоже нельзя залудить.
R>4) Реализуется с использованием функции-члена, что противоречит принципам обобщенного программированя;
Конечно же конструктор-копии -- это не функция-член
В любом случае, если мы хотим написать функцию, которая "крадёт" данные из объекта, она должна иметь доступ к private-части класса.
R>5) Резервирует имя функции-члена, создвавая предпосылки для конфликтов имен; R>6) Плохо подходит для работы с разными типами данных. Как только src и dst станут иметь разные тут же выяснится, что в каких-то случаях удобнее иметь "move_to", а каких-то "move_from";
Так это же означает, что в случае конструктора копии удобный вариант в половине случаев вообще не получится выбрать.
Он вообще всегда имеет только вариант move_from, называемый "перемещающий оператор присваивания"
Кстати, я уже выше писал, что согласен, что просто move плохое название для такого метода. Лучше, конечно move_to/move_from/swap
R>7) Не подходит для автоматической генерации компилятором. Пониммаю, что для тебя это плюс, но не разделяю твою точку зрения. Потому, что сейчас поддержка move семантики в большинстве случаев либо генерируется автоматически, либо сводится к тривиальному разрешить/запретить. В твоем же варианте реально нужно будет все это писать. Раздувая объем кода и натягивая массу ошибок;
Это место я не понял. Ты про то, что в STL-контейнерах Степанов забыл поддержать такую возможность, как move_to, или про что?
R>8) Вынуждает заводить лишние локальные переменные, что крайне плохо сказывается на структуре кода.
Это тоже не понял. Но как переменная (имеющая имя и смысл) портит структуру кода, ни зачем их заводить?
Мы же говорим о таких примерах кода, где RVO невозможен, да?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А чем плох конструктор по умолчанию? На мой взгляд плох не такой конструктор, а то, что нужно поддерживать в классе некое выделенное "значение по умолчанию".
Плох не конструктор сам по себе, а то, что он становится обязательным. Появляется ограничение там, где его раньше не было. Бывают такие классы, для которых конструкторы по умолчанию лишены смысла, и их поддержка наносит прямой вред.
Здравствуйте, Videoman, Вы писали:
V>Т.е. dst уже ложен быть на момент создания. А как через такой синтаксис выразить: V>
V>SomeClass b = ....
V>//...
V>SomeClass a = b + SomeClass(...); // такое?
V>
Такое прекрасно работало и до move-семантики через RVO и copy elision…
V>
V>SomeClass a = ....
V>func(std::move(a)); // такое?
V>
Такой, на мой вкус, вообще сомнительно. Смотри, например, вопрос о том, с чего началась эта ветка...
V>А что делать если нам не повезло и у dst нет конструктора по умолчанию? И src у тебя превращается в такое же зомби с неопределенным состоянием. Так чем же твой подход лучше?
Тем, что не надо усложнять язык...
Хуже то, что в этом раскладе move-семантика ничем не лучше, но сложнее
Если что, то в этой подветке вроде обсуждалось то, что косяки дизайна контейнеров STL не богоданные, а вполне могут быть выпрямлены при желании...
IMHO, это очевидно.
Но я в плоском режиме читаю, могу подветки спутать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, B0FEE664, Вы писали:
BFE>Причём тут RVO? Или это вы так copy elision называете?
Ну всю группу таких оптимизаций. RVO, NRVO, copy elision и т. д...
В С++ часто бывает так, что мы вместо того, что бы несколько раз копировать созданный объект, сразу создаём его в нужном месте.
Но формально там среди нескольких конструкторов была и функция ну и operator + у класса тоже как бы функция или метод
p. s.
Тут вроде на "ты" обращение принято?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, Erop, Вы писали:
E>>То, что у нас, как программистов на С++ нет механизмов для прямого написания похожих функций, ну, например, мы не можем написать метод move_to_res(), который возвращает объект, в который перемещает себя. E>>Ну, то есть мы сейчас можем написать { return std::move(*this); } E>>Но для этого нам надо писать конструктор перемещения и всё такое. Напрямую мы такую функцию написать не можем. BFE>Можем:
Во-первых, этот код вовсе не перемещает себя в результат, он просто возвращает хитрую ссылку на себя же:
Я заменил печать на
Во-вторых, это вовсе и не "напрямую"...
Напрямую было бы, например, если бы я передавал в функцию адрес (или как-то внутри функции мог бы его получить) того места, где ловят результат снаружи.
Как с this в конструкторах сделано, например...
Кстати, при таком подходе можно было бы возвращать сразу несколько результатов.
E>>Что касается критики идеи с методом move у вектора, то код
std::vector<T> dst;
E>>src.move_to( dst )
ничем особо не хуже метода
std::vector<T> dst = std::move( src );
кроме того, что первое сразу понятно, а второе надо знать пр std::move, конструкторы перемещения и т. д... BFE>А как быть, если dst — аргумент функции?
А что от этого меняется? Ты правда пытаешься оспорть то, что в контейнерах можно было поддержать возможность move чисто сресдствами библиотеки, не меняя языка?
И это при живых методе и функции swap?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, rg45, Вы писали:
R>Плох не конструктор сам по себе, а то, что он становится обязательным. Появляется ограничение там, где его раньше не было. Бывают такие классы, для которых конструкторы по умолчанию лишены смысла, и их поддержка наносит прямой вред.
Так конструктор перемещения плох примерно тем же жеж?
Мне, на самом деле, вообще концепция перегруженных конструкторов не особо нравится. Так как функция одинаково называется/вызывается, а делать может разное. Это противоречит обычной практике перегрузки функций...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Так конструктор перемещения плох примерно тем же жеж?
С чего вдруг? У конструктора такие же возможности по инициализации любых членов-данных, в т.ч. ссылок и констант, как и у любого другого конструктора. Только, в отличие от конструктора по умолчанию, у него есть входные данные для такй инициализации.
Здравствуйте, rg45, Вы писали:
R>С чего вдруг? У конструктора такие же возможности по инициализации любых членов-данных, в т.ч. ссылок и констант, как и у любого другого конструктора. Только, в отличие от конструктора по умолчанию, у него есть входные данные для такй инициализации.
С того, что он должен оставить "зомби" на старом месте? Или там пофиг чем константы/ссылки инициализированы? Например ссылки на несуществующие объекты -- это нормально?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>С того, что он должен оставить "зомби" на старом месте? Или там пофиг чем константы/ссылки инициализированы? Например ссылки на несуществующие объекты -- это нормально?
Не "должен", а "может". Важно, что есть возможность полноценно сконструировать новый объект. А что именно остается на старом месте ни чем регламентировано, это может быть что угодно — от полного копирования, до полной выемки всех данных. Собственно, в этом мой вопрос и заключался — что может, а чего не может оставаться на старом месте после перемещения.
Здравствуйте, Erop, Вы писали:
E>>>Так что и дальше можно обсуждать механизмы по управлению RVO... V>>Ну вот приведи разумный пример, когда RVO не нужна? E>Не понял, что значит "не нужна"?
Ну ты хочешь зачем-то управлять RVO. RVO применяется всегда, когда это возможно — значит ты хочешь RVO отключать
E>Ну я же приводил пример. У тебя есть авторегистрилки и уведомлялки. E>Когда ты из них выводишь объекты, которые получают и рассылают эти все уведомления, и потом их копируешь дефолтным конструктором копии, то в момент создания копии весь оригинал ещё существует в виде MDT, и он весь корректно работает и все рассылки уведомлений между его частями тоже. А когда ты перемещаешь конструктором перемещения, то в процессе перемещения какие-то части уже подписаны, а какие-то ещё нет, в результате инварианты вроде "всех уведомили о" могут теряться...
Не, ну тут у тебя явно ошибка в логике. Ты где-то перемещаешь "душу", а this у тебя где-то старый зависает. Это не относится только к move-у. Совет, используй в таких случаях Impl и всю подписку делай в нем, тогда таких проблем не будет, т.к. он мувается на ура.
E>Я понял в чём суть разногласий. Ты считаешь, что move-семантику ввели практически за бесплатно, а я считаю, что усложнили и весьма заметно, язык.
Да, видимо так. Но все у меня все стало хорошо, как только я перестал переть против "паровоза", немного вник и стал действовать в русле разработчиков стандарта С++.
E>Да, STL -- штука весьма кривая. Это правда.
Здравствуйте, rg45, Вы писали:
R>Не "должен", а "может". Важно, что есть возможность полноценно сконструировать новый объект. А что именно остается на старом месте ни чем регламентировано, это может быть что угодно — от полного копирования, до полной выемки всех данных. Собственно, в этом мой вопрос и заключался — что может, а чего не может оставаться на старом месте после перемещения.
Ну ты же понимаешь, что на старом месте позовут потом деструктор?..
Это как бы единственное ограничение.
Но если оставить что-то такое, с чем потом легко злоупотребить, например ссылку на несуществующий объект, то легко устроить потом нечаянно большой бара-бум, как говорила героиня Миллы Йолович в "Пятом элементе"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Videoman, Вы писали:
V>Ну ты хочешь зачем-то управлять RVO. RVO применяется всегда, когда это возможно — значит ты хочешь RVO отключать
Ты, наверное в российском правительстве работаешь, да? Я других таких людей не знаю, у кого "управлять" означает "запрещать"
Я приводил несколько вариантов возможного управления механизмами вроде RVO тут, в дискуссии, если что.
V>Не, ну тут у тебя явно ошибка в логике. Ты где-то перемещаешь "душу", а this у тебя где-то старый зависает. Это не относится только к move-у. Совет, используй в таких случаях Impl и всю подписку делай в нем, тогда таких проблем не будет, т.к. он мувается на ура.
Проблема в том, что был старый код, вполне работоспособный, в библиотеку подписки прикрутили move-семантику, тоже более или менее работоспособную, но в сложных случаях старый код перестал работать. Вполне логично и верифицируемо и понятно перестал, но выявлять и чинить пришлось руками.
Это к тому, что всё оно работает за нас и никогда не возникает само по себе, это всё в реальности обычно сказки
V>Да, видимо так. Но все у меня все стало хорошо, как только я перестал переть против "паровоза", немного вник и стал действовать в русле разработчиков стандарта С++.
Я тоже не "пру против паровоза", хотя в том проекте, где я широко пользовался С++ крайний раз, STL не использовался, по многим причинам
Но мы же тут обсуждали
1) Был задан вопрос, какие требования нынешний С++ накладывает на оставляемый move-конструктором "зомби"
2) И как подветку, я высказал тезис, что сам по себе этот вопрос показывает некоторую концептуальную непроработанность move-семантики
После чего мы стали обсуждать умозрительные соображения, как бы можно было решить те же проблемы, иными путями и что ещё можно было бы сделать похожего.
В этой повестке обсуждать паровоз комитета довольно перпендикулярно теме. Был бы у комитета иной паровоз, можно было бы следовать и за ним тоже...
E>>Да, STL -- штука весьма кривая. Это правда. V>
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, rg45, Вы писали:
TSP>>В писании сказано: TSP>>
TSP>>Objects of types defined in the C++ standard library may be moved from (12.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
TSP>>Как я понимаю, в общем случае нужно заботиться о целостности объекта после его перемещения. R>Ну так вот вопрос о понимании этой самой целостности. Одно дело, целостность для того, чтобы похоронить объект и совсем другое — целостность для того, чтобы продолжать им пользоваться.
Для объектов стандартной библиотеки "valid" означает что им можно продолжать пользоваться. Например вектору легально можно сделать .clear(), или .resize(), .size().
R>Этот вопрос можно сформулировать и по-другому: стоит ли требовать от разработчиков, в самом общем случае, документирования состояния объектов после перемещениея?
Документировать конечно стоит. Причём "документацией" может быть одно предложение на весь проект а-ля "Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state".
R>Или исплользование объектов после перемещения — это зло, с которым нужно бороться?
Нет, не зло если разрешено документацией.
R>Или могут быть варианты? R>P.S. Понятно, что из любого правила могут быть исключения. Но хотелось бы понимать, все-таки, каково же само правило.
Правило стандартной библиотеки привели выше.
Если в проекте используется такая же конвенция как и в стандартной библиотеке, то для тех типов для которых это не выполняется (т.е. "Unless otherwise specified") — может в Debug режиме добавить в методы assert(this->is_valid()).
Если брать непосредственно технический аспект rvalue references — то думаю даже destructability не является формальным требованием языка, а вызов методов не является формальным запретом.
В большинстве же случаев ожидается как минимум нормальная desctructability и возможность move assignment.
Здравствуйте, Erop, Вы писали:
V>>Зачем управлять тем, чем компилятор и так управляет оптимально: V>>- сначала пробует RVO/NRVO E>Например было бы круто как-то сказать компилятору, что в этом месте надо обломаться, если не получилось. E>И в этом случае, кстати, можно было бы не требовать наличие открытого конструктора копии
Начиная с C++11 есть list-initialization: live demo
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А начиная с C++17 есть гарантированное RVO: EP>live demo EP>
EP>NonCopyableNonMovable foo()
EP>{
EP> returnNonCopyableNonMovable{1, .5};
EP>}
EP>int main()
EP>{
EP> auto x = foo();
EP>}
EP>
Разрыв шаблонов и подрыв устоев какой-то
И что в таком случае должно помешать сделать вот так?:
int main()
{
NonCopyableNonMovable t{1, .5};
auto x = std::move(t);
}
Разница ведь между std::move и foo только в том, что std::move возвращает rvalue ссылку, тогда как foo возвращает по значению. Теперь эти случаи будут обрабатываться по разным правилам?
Здравствуйте, rg45, Вы писали:
R>И что в таком случае должно помешать сделать вот так?:
R>
R>int main()
R>{
R> NonCopyableNonMovable t{1, .5};
R> auto x = std::move(t);
R>}
R>
Конкретно в этом примере нужен конструктор перемещения, ибо t всё ещё жив, точнее там в области живы оба объекта.
R>Разница ведь между std::move и foo только в том, что std::move возвращает rvalue ссылку, тогда как foo возвращает по значению.
EP>Теперь при возврате по значению И сохранению по значению компилируется, а раньше нет — ибо теперь возможно гарантированное RVO.
Принцип я понял. И, безусловно, рад такой возможности. Но меня интересовало, как эти требования будут сформулированы в стандарте. Но вот что-то не находится в драфте 17-го ни "RVO", ни "return value optimization".
Здравствуйте, rg45, Вы писали:
R>Принцип я понял. И, безусловно, рад такой возможности. Но меня интересовало, как эти требования будут сформулированы в стандарте. Но вот что-то не находится в драфте 17-го ни "RVO", ни "return value optimization".
В стандарте используется термин copy/move elision.
R>Принцип я понял. И, безусловно, рад такой возможности. Но меня интересовало, как эти требования будут сформулированы в стандарте. Но вот что-то не находится в драфте 17-го ни "RVO", ни "return value optimization".
Да и SFINAE в стандарте не находится. И много чего ещё.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Теперь при возврате по значению И сохранению по значению компилируется, а раньше нет — ибо теперь возможно гарантированное RVO.
И за счет чего это достигается? Работает ли это при кросс-модульной не PGO компиляции?