семантика владения unique_ptr

Возможно, я пытался быть слишком общим. (Оригинальный вопрос ниже) Конкретно, у меня есть некоторая зависимость Dep класса Foo, У меня тоже есть класс MockDep и я определяю класс TestFoo, Вот его конструктор, который я попытался написать:

TestFoo(unique_ptr<MockDep> dep) : Foo(std::move(dep)), mock_dep_(dep.get()) {}

А также FooКонструктор выглядит так:

Foo(unique_ptr<Dep> dep) : dep_(dep) {}

mock_dep_ Delcared в TestFoo как MockDep* mock_dep_, а также dep_ объявлен в Foo как unique_ptr<Dep> dep_, Как я могу получить mock_dep_ содержать dep_адрес? (так как выше не работает, так как std::move(dep) обнуляет dep.)


Исходное сообщение:

У меня есть объект типа Foo что я должен передать другому объекту типа OtherObject который претендует на владение им, но как указатель на его базовый класс. Однако я хочу получить указатель на дочерний объект, который я могу использовать для ссылки на него. Я написал что-то вроде:

Foo(std::unique_ptr<Child> thing) :
OtherObject(std::move(thing)), child_(thing.get()) {}

OtherObject(std::unique_ptr<Base> thing, ...) { ... }

Тем не менее, это не похоже на работу, так как std::move(thing) кажется, обнулить указатель, который возвращается из thing.get() потом.

я могу изменить Fooпараметр, чтобы иметь тип Child* вместо unique_ptr<Child>, но я предпочел бы иметь возможность сделать последнее, поскольку оно явно документирует семантику владения.

Каков наиболее подходящий (или неудачный, ненавязчивый) способ решения этой проблемы?

редактировать: Foo а также OtherObject оба должны быть классами, чьи конструкторы я определяю.

5

Решение

Вы можете использовать:

Foo(std::unique_ptr<Child> thing) :
OtherObject(std::move(thing)),
child_(OtherObject.getChildPtr()) /* one accessor to get the pointer. */
{}

Если базовый объект OtherObject не предоставляет средства доступа к указателю, вы можете делегировать конструктор другому конструктору, например:

class Foo: public OtherObject
{
public:
Foo(std::unique_ptr<Child> thing) : Foo(thing, thing.get()) {}

private:
Foo(std::unique_ptr<Child>& thing, Child* child) :
OtherObject(std::move(thing)),
child_(child)
{}
private:
Child* child_;
};

Третьим решением было бы изменить порядок между OtherObject а также child_ (иметь child_ до) путем введения другого деривации:

class ChildPtr
{
public:
ChildPtr(Child* child) : child_(child) {}

Child* child_;
};

class Foo: private ChildPtr, public OtherObject
{
public:
Foo(std::unique_ptr<Child> thing) :
ChildPtr(thing.get()),
OtherObject(std::move(thing))
{}
};
6

Другие решения

Обычно то, что происходит, описано в стандарте как:

§17.6.5.15.1 Состояние перемещенных из библиотеки типов [Lib.types.movedfrom]

Объекты типов, определенных в стандартной библиотеке C ++, могут быть перемещены из (12.8). Операции перемещения могут быть явно указаны или неявно сгенерированы. Если не указано иное, такие перемещенные объекты должны быть помещены в допустимое, но неопределенное состояние.

Стандарт на самом деле конкретно описывает поведение std::unique_ptr в:

§20.8.1.4 Шаблон класса unique_ptr [Unique.ptr]

Дополнительно, u может, по запросу, передать право собственности другому уникальному указателю u2, После завершения такого перевода выполняются следующие постусловия:

  • u2.p равна предварительной передаче u.p,
  • u.p невероятно похож на nullptr, а
  • если состояние предварительной передачи u.d поддерживалось, такое состояние было передано в u2.d.

В частности, depпосле строительства Foo подобъект в:

Foo(std::move(dep))

это nullptr,

Более того, если dep был еще действительным указателем, Foo(std::move(dep)) скопировал бы depчто не имеет смысла для std::unique_ptrсемантическая (как не копируемая).

То, что вы хотите сделать, это позволить ссылку на указанный объект с учетом обстоятельств дела (например, может ли unique_ptr быть nullpt? и т. д.), в Foo:

class Foo {
public:
Foo(unique_ptr<Dep> dep) : dep_(dep) {}
const Dep& get_dep() const { return *dep_; }
Dep& get_dep()             { return *dep_; }
private:
std::unique_ptr<Dep> dep_;
};

а затем просто построить TestFoo объект как:

TestFoo(unique_ptr<MockDep> dep) : Foo(std::move(dep)) {}
1

По вопросам рекламы [email protected]