C++ 唯一的\u ptr所有权语义

C++ 唯一的\u ptr所有权语义,c++,smart-pointers,unique-ptr,ownership-semantics,C++,Smart Pointers,Unique Ptr,Ownership Semantics,也许我想说得太笼统了。(下面的原始问题)具体来说,我对类Foo有一些依赖性Dep。我还有一个类MockDep,正在定义一个类TestFoo。下面是我试图编写的构造函数: TestFoo(unique_ptr<MockDep> dep) : Foo(std::move(dep)), mock_dep_(dep.get()) {} mock\u dep\u在TestFoo中作为MockDep*mock\u dep\u进行删除,而dep\u在Foo中作为唯一的\u ptr dep\u进行

也许我想说得太笼统了。(下面的原始问题)具体来说,我对类
Foo
有一些依赖性
Dep
。我还有一个类
MockDep
,正在定义一个类
TestFoo
。下面是我试图编写的构造函数:

TestFoo(unique_ptr<MockDep> dep) : Foo(std::move(dep)), mock_dep_(dep.get()) {}
mock\u dep\u
TestFoo
中作为
MockDep*mock\u dep\u
进行删除,而
dep\u
Foo
中作为
唯一的\u ptr dep\u
进行声明。我如何才能使
mock_dep_
包含
dep_
的地址?(由于上述操作不起作用,因为
std::move(dep)
null out
dep


原创帖子:

我有一个
Foo
类型的对象,我要将它传递给另一个
OtherObject
类型的对象,该对象声明它的所有权,但作为指向其基类的指针。但是,我想获取一个指向子对象的指针,我可以用它来引用它。我写了这样的东西:

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

OtherObject(std::unique_ptr<Base> thing, ...) { ... }
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_;
};
Foo(std::unique\u ptr thing):
其他对象(std::move(thing)),子对象(thing.get()){}
其他对象(std::unique_ptr thing,…{…}
但是,这似乎不起作用,因为
std::move(thing)
似乎会清空稍后从
thing.get()返回的指针

我可以将
Foo
的参数更改为
Child*
类型,而不是
unique\u ptr
,但我更希望能够执行后者,因为它明确地记录了所有权语义

解决这个问题的最合适的方法是什么

edit
Foo
OtherObject
都是我正在定义其构造函数的类。

您可以使用:

Foo(std::unique_ptr<Child> thing) :
    OtherObject(std::move(thing)),
    child_(OtherObject.getChildPtr()) /* one accessor to get the pointer. */
{}
第三种解决方案是通过引入其他派生来更改
其他对象
子对象
(之前有
子对象
)之间的顺序:

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))
    {}
};
class-ChildPtr
{
公众:
ChildPtr(Child*Child):Child_(Child){}
儿童*儿童;
};
类Foo:private ChildPtr,public OtherObject
{
公众:
Foo(std::unique\u ptr thing):
ChildPtr(thing.get()),
其他对象(std::move(thing))
{}
};

标准中通常将发生的情况描述为:

§17.6.5.15.1从库类型状态移动[lib.types.movedfrom]

<> C++中定义的类型对象可以从(12.8)移动。可以显式指定或隐式生成移动操作。除非另有规定,否则从物体上移动的物体应处于有效但未指定的状态

该标准实际上具体描述了
std::unique_ptr
在以下方面的行为:

§20.8.1.4类模板唯一性\u 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\u ptr
的语义没有意义(因为它是不可复制的)

您要做的是在适当考虑情况下(例如,唯一的\u 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_;
};

其他对象是什么?“好吧,在那种情况下,它不可能是一个函数。”“杰弗里,我的错,博特。”edited@Jefffrey我不确定还有什么困惑——我重写了这篇文章,以便更直接地提到我的问题。你说的“依赖性”是什么意思?@mattmcnab“依赖性”从某种意义上讲,基本上只是类需要使用的某个对象。
OtherObject
根据OP是基类。
OtherObject
是指某种任意类型,而不是
唯一的\u ptr
。使用我编辑的文章中的术语,我想避免修改
Foo
,以提供一个getter(主要是因为它需要静态转换),但另一种解决方案也不太吸引人,所以我可能只使用转换访问器。@alecb:我添加了另一种可能更适合您的用例的替代方案。我相信
unique\u ptr
特别保证它是空的?
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(unique_ptr<MockDep> dep) : Foo(std::move(dep)) {}