unique_ptr所有权语义

时间:2014-06-09 23:03:17

标签: c++ smart-pointers unique-ptr ownership-semantics

也许我试图过于通用。 (下面的原始问题)具体来说,我有一个类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_TestFoo中被MockDep* mock_dep_视为dep_,而Foounique_ptr<Dep> dep_中被视为mock_dep_。如何让dep_包含std::move(dep)的地址? (由于depFoo归零,因此上述方法无效。)


原帖:

我有一个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和{{1}}都是我正在定义构造函数的类。

2 个答案:

答案 0 :(得分:6)

您可以使用:

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_;
};

第三种解决方案是通过引入其他推导来更改OtherObjectchild_之间的顺序(之前有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))
    {}
};

答案 1 :(得分:1)

通常情况会在标准中描述为:

  

§17.6.5.15.1移动 - 来自库类型的状态 [lib.types.movedfrom]

     

可以从(12.8)移动C ++标准库中定义的类型的对象。可以显式指定或隐式生成移动操作。除非另有规定,否则此类移动对象应置于有效但未指定的状态。

该标准实际上具体描述了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的语义没有意义(因为它不是-copyable)。

你要做的是在nullpt中考虑到案例(例如,unique_ptr可以是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)) {}