Мой вопрос: я пропускаю что-то простое, и есть ли лучший способ перегрузить оператор присваивания для пользовательских типов, которые имеют член unique_ptr?
Да, действительно.Это нарушает понимание того, что делают умные указатели в C++
.Обычно вы используете std::unique_ptr
, если будет одна и только одна ссылка на ваш объект.По этой причине std_unique_ptr
s не могут быть ни копируемыми, ни копируемыми.Если вы вручную создадите две копии std::unique_ptr
, как вы описали в своем посте, используя ptr.get()
, вы окажетесь в недопустимом состоянии, потому что, как только одна копия покидает область действия, деструктор std::unique_ptr
также разрушит объектон указывает, оставляя другой std::unqiue_ptr
в недопустимом состоянии (он указывает на свободную ячейку памяти).Поэтому, если может быть несколько ссылок на ваш объект, вам, вероятно, следует использовать std::shared_ptr
.
В ваших примерах вопрос состоит в том, чего вы хотите достичь?
Если вы хотите использовать свой оператор присваиваниятаким образом, что после вызова a = b
, a.ptr
и b.ptr
указывают на один и тот же объект (т.е. сохраняют один и тот же указатель), используйте общий указатель.Вам определенно НЕ следует использовать уникальный указатель в этом случае, так как вызов деструктора для a
или b
приведет к разрушению указанного объекта, оставив a
или b
в недопустимом состоянии.
Если вы хотите, чтобы после вызова a = b
, a.ptr
указывал на независимую копию *(b.ptr)
, вы действительно можете использовать уникальный указатель и реализовать свой оператор присваивания, как этот (при условии, что baseClass
является копируемым):
object& object::operator=(const object& _obj)
{
//POD types use operator= as normal
ptr.reset(new baseClass(*_obj.ptr));
return *this;
}
Обратите внимание, что это работает, только если baseClass
равно final
(маловероятно, учитывая имя ...), то есть ptr
не будет хранить указатели на объекты производного класса.В противном случае это приводит к срезам , на что указывает BenVoigt.
Наконец, обычно ожидается, что вызов a = b
действительно не изменит b
.Поэтому сделать изменяемый элемент ptr
и использовать swap
звучит для меня как плохая идея.Если вы хотите добиться такого поведения из-за соображений производительности (или других), я бы предложил вместо этого ввести оператор присваивания перемещения
object& object::operator=(object&& _obj)
{
//POD types use operator= as normal
ptr = std::move(_obj.ptr);
return *this;
}
и вызвать a = std::move(b)
, что дает понять, что b
может закончитьсяв другом состоянии.