指向所有者的指针

Pointer to owner

本文关键字:指针 所有者      更新时间:2023-10-16

考虑以下类结构:

struct owner;
struct owned;
struct owned {
    owner* my_owner;
};
struct owner {
    owned owned_object;
};

owned只能用作owner的成员,对于所有owner对象o,应保持以下不变量:

o.owned_object.my_owner == &o; 

我的问题是:

  1. 这个图案有名字吗
  2. 关于如何最好地实现owner/owned的构造函数,是否有编程实践

对于2.,我的重点是简单优雅的代码,而不是一流的效率。例如,我希望尽可能多地使用隐式声明的构造函数。

附言:这个问题可以看作是指针指向所有者类的后续问题。

我不确定是否有实际的名称,因为它不是一个非常有用的模式,因为它非常有限:类现在在两个方向上都完全依赖。好的一面是,这是一个简单的解决方案,坏的一面是这是循环依赖的一个例子,可以被视为反模式。

如果您要创建一个接口IOwnedOwner(不是一个有用的名称,但描述了当前情况),让owner继承并让owner使用该接口,那么您将拥有一个回调系统。至少在这里,任何想要拥有的人都必须从接口继承。

使用Observer模式,所有类型的相关方都可以注册所属对象的通知,这将使其更加灵活。

在上面显示的情况下,有一个简单的解决方案:在owner类中,引入指针copy_并修改复制构造函数/赋值运算符,使copy_始终指向owner对象的最后一个副本。当复制owned时,我们通过old_object.my_owner.copy_获得新对象的地址。

为了最大限度地提高代码重用性,我们引入了owner基类和owner_ptr类,如下所示。

class owner {
public:
    owner() = default;
    owner(const owner& to_copy) { to_copy.copy_ = this; }
    owner& operator=(const owner& to_copy) { to_copy.copy_ = this; return *this; }
private:
    mutable owner* copy_;
    template<class> friend class owner_ptr;
};
template<class Owner>
class owner_ptr {
public:
    owner_ptr(Owner* o) : owner_(o) {}
    owner_ptr(const owner_ptr& to_copy) : owner_(to_copy.owner_->copy_) {}
    owner_ptr& operator=(const owner_ptr& to_copy) { owner_ = to_copy.owner_->copy_; return *this; }
    Owner& operator*() const { return static_cast<Owner&>(*owner_); }
    Owner* operator->() const { return static_cast<Owner*>(owner_); }
private:
    owner* owner_;
};

获得所需的所有者/所有者关系现在只需要对原始代码进行微小的更改。

struct some_owner;
struct some_owned;
struct some_owned {
    some_owned(some_owner* o) : my_owner(o) {}
    owner_ptr<some_owner> my_owner;
};
struct some_owner : owner {
    some_owner() : owned_object(this) {}
    some_owned owned_object;
};

不过,这种方法有一些注意事项:

  • 同一some_owner对象的所有副本都必须按顺序发生,即同一对象没有多线程副本,也没有嵌套副本
  • 所示的方法仅在移动some_owner类涉及移动some_owned类的情况下有效。如果不是这样的话,例如,当some_owned存储在向量中时,我们必须为owner类被移动的事件实现一个老式的观测器模式。编码ownerowner_ptr需要更多的工作,但生成的代码与以前一样易于使用,并且开销仅略有增加