Здравствуйте, Videoman, Вы писали:
W>>Если другой wrapper_ptr не удаляет память в деструкторе, то указатель можно и не менять — всё будет работать. Если wrapper_ref содержит ссылку — то тем более её нет нужды менять — её «удаление» не уронит программу просто из-за того, что разрушение ссылки в деструкторе — суть отсутствие каких-либо действий.
V>А как быть в случае ссылки и movе оператора?
Достаточно ничего не делать.
V>Я же не могу переприсвоить ссылку?
Для случаев же, когда без этого не обойтись, есть std::reference_wrapper — эту ссылку можно менять.
W>>Тут примерно то же самое — объект остался в консинстентном состоянии, но неизвестно какое это состояние. Так, например, то же перемещение из vector<T> может как сделать объект пустым, так и наполнить его какими-нибудь данными. Оба случая встречаются на практике. В обоих случаях поведение является допустимым, а состояние объекта остаётся согласованным, но вот использовать этот объект просто так не стоит — ведь записав в него через push_back какие-то данные не будет гарантии, что в нём не останется какой-то другой мусор.
W>>Вот именно из-за этого и не стоит использовать объекты после move.
V>Т.е. у такого объекта, в случае со ссылкой, должен быть организован некий zomby mode ?
Нет же.
То есть сделать так можно, но обычно не нужно. В C++ есть много мест где можно прострелить себе ногу, и это не самое популярное. Проверки и подстраховки — это хорошо, но для них есть и более приоритетные места.
Вот есть три популярные реализации стандартной библиотеки С++11: libstdc++, libc++ и вариант от visual c++. Ни в одной из них ничем подобным не занимаются. Можешь сам открыть реализацию, например, уже упомянутого std::reference_wrapper и убедится, что для перемещения ссылок там не задано никаких дополнительных действий, а ссылка-источник никак при этом не изменяется. И все нормально с этим живут. И даже по стандарту.
А тут ситуация больше похожа на то, что сначала выдумал проблему с перемещением ссылок, а теперь пытаешься её героически решить. Хотя самой проблемы нет — просто не трогай ссылки.
Я понимаю, что ты хочешь обезопасится от пользователя, который внезапно захочет работать с объектом из которого сделали move. Но у такого пользователя будут проблемы не только с твоей библиотекой. И проще считать, что не твоя библиотека должна учить его новым основам C++11
V>>>У классов без ссылок я могу переинициализировать члены — я так и делаю.
W>>Ясно, а зачем? Использовал обёртку и выкинул, вместо этого создал другую. Такой вариант тебе не подходит? Ну тогда используй просто указатели вместо ссылок — и вопрос решён.
V>Подходит, но не думал что с ссылкой придется возится с тем, чтобы обеспечить контроль на случай, если перенесенный объект кто-то дернет случайно.
V>Сложность еще в том что до этого класс не имел конструктора по умолчанию и не было логики которая проверяла валидный объект или нет (кроме assert-ов).
V>Теперь придется везде добавлять проверки. Я правильно понимаю?
Дешевый вариант — переехать на указатели и занулять их из move-коснтруктора. Тогда разыменование такого указателя хотя и будет UB, но достаточно часто всё-таки будет приводить к segfault, что вроде как желаемое поведение. Хотя иногда вместо segfault будет феерически глючить, ибо UB.
Но, да, если тебе нужно определенное поведение и гарантии что с таким объектом никто уже не будет работать, то придётся делать проверки на валидность. Для этого можно либо ввести дополнительный булев флаг (подобно всяким optional<T> и maybe<T> контейнерам), либо, опять же, перейти на указатели и проверть их каждый раз на nullptr перед разыменованием (можно, например, тот же reference_wrapper взять за основу, дописать в него соответствующие конструкторы из r_w<T>&& и засунуть проверку в .get).