0

假设我有一个 typeAggregator和一个Aggregatee。前者知道 s 对后者的集合shared_ptr。后者有一个指向前者的唯一反向指针:

struct Aggregatee {
  private:
    Aggregator& aggregator;
    Aggregatee(Aggregator& aggregator)
      : aggregator{aggregator} {
      // PROBLEM HERE:
      //   I want to put `this` into the aggregation list,
      //   but I have no clue how to properly refer to `this`
      //   because I don't have the smart pointer object, yet.
    }
    Aggregatee(Aggregatee const& from) { /* ... */ }
  public:
    template <typename Args...>
    static std::shared_ptr<Aggregatee> create(Args... args) {
      return std::make_shared<Aggregatee>(args...);
    }
};

struct Aggregator {
  std::set<std::shared_ptr<Aggregatee>> aggregation;
};

显然,我可以在使用私有函数之后推迟AggregateeAggregator对象中注册,但它闻起来像两阶段,因为对象临时不一致地初始化make_sharedregister

有什么已知的解决方案吗?

4

3 回答 3

0

您要避免的实际上是一种非常常见的模式:创建聚合器(容器),然后创建聚合(元素)并将其插入容器中。可以使用传递给构造函数的反向指针创建元素,然后将其插入容器或反向指针。

例如,考虑一个带有反向指针的二叉树,元素在叶子上创建并带有指向父节点的指针,并且指针立即存储在父节点中。

至于您的特定问题,它无法完成,因为shared_ptr在创建对象之前您无法获得对象,即使使用enable_shared_from_this.

于 2012-09-07T03:42:41.247 回答
0

您可以使用侵入式共享指针。由于引用计数存在于共享对象中,因此 Aggregatee 可以在其自己的构造函数中创建指向自身的共享指针。

Boost 有一个侵入式指针类型的例子,或者你可以很容易地滚动你自己的。

http://www.boost.org/doc/libs/1_51_0/libs/smart_ptr/intrusive_ptr.html

// shared base type contains the reference counter; how you implement the
// reference counting depends on your implementation.
struct Aggregatee : public shared {
  private:
    Aggregator& aggregator;

    Aggregatee(Aggregator& aggregator) : aggregator{aggregator} {
      // Boost allows a raw pointer to be implicitly cast to an intrusive
      // pointer, but maybe your intrusive pointer type won't.
      aggregator.aggregation.insert(intrusive_ptr<Aggregatee>(this));
    }

    Aggregatee(Aggregatee const& from) { /* ... */ }

  public:
    template <typename Args...>
    static intrusive_ptr<Aggregatee> create(Args... args) {
      return new intrusive_ptr<Aggregatee>(args...);
    }
};

struct Aggregator {
  std::set<intrusive_ptr<Aggregatee>> aggregation;
};

您必须注意的一件事是,Aggregatee 在构造后确实存储在智能指针中。

Aggregatee aggregatee(aggregator);  // Very bad!
intrusive_ptr<Aggregatee> aggregatee(new Aggregatee(aggregator));  // Good

此外,您最好确保您的 Aggregator 持有 intrusive_ptr 直到 Aggregatee 完全构造,否则 Aggregatee 最终将在构造函数退出之前被销毁!

因此,这种方法有一些注意事项,但据我所知,这是您最接近实现您所要求的目标的方式。

于 2012-09-07T15:34:41.973 回答
0

根据您的应用程序,您可以将静态创建方法从 Aggregatee 移动到常规成员方法 Aggregator。然后您可以创建 shared_ptr 并将其存储在相同的方法中。

这假定 Aggregatee 始终与 Aggregator 相关联。

于 2012-09-07T02:00:46.687 回答