智能指针是否能够从容器中删除对象的其他引用?

时间:2016-12-09 11:59:15

标签: c++ c++11 pointers c++14 smart-pointers

我想实现这个:

  • 对象A拥有一个对象B(有一个指向它的指针)
    • 当对象A被销毁时,对象B也会被销毁。
  • 对象C有一个指向Object B-s的std :: vector指针。
    • 当对象B被销毁时,从对象C的向量中移除其指针。

这是否可以结合使用不同的智能指针?

2 个答案:

答案 0 :(得分:2)

让我们考虑角色(现在忽略线程):

对象A拥有B的生命周期

对象C是B生命周期的观察者

你没有说A和C之间是否存在关系,所以我假设A知道C在其构造函数中的含义(让我们使用C作为可配置的工厂)。

B的生命事件有两个地方可以创建观察 - B的构造函数/析构函数(坏 - 紧耦合)或中间工厂(更好 - 松散耦合)。

所以:

#include <memory>
#include <algorithm>

struct B {

};

struct C {
    std::shared_ptr<B> make_b() {
        auto p = std::shared_ptr<B>(new B(), [this](B *p) {
            this->remove_observer(p);
            delete p;
        });
        add_observer(p.get());
        return p;
    }

private:
    void add_observer(B *p) {
        observers_.push_back(p);
    }

    void remove_observer(B *p) {
        observers_.erase(std::remove(std::begin(observers_), std::end(observers_), p),
                         std::end(observers_));
    }

    std::vector<B *> observers_;
};

struct A {
    A(C &factory)
            : b_(factory.make_b()) {}


    std::shared_ptr<B> b_;

};


int main() {

    // note: factory must outlive a1 and a2
    C factory;

    A a1(factory);
    A a2(factory);
}

请注意,虽然我使用了shared_ptr,但在这种情况下我可以轻松使用unique_ptr。然而,我会将A与指针中的删除类型相结合 - 所以我要么必须创建我自己的类型删除删除类型,要么更紧密地耦合A到C(我想避免)。

答案 1 :(得分:1)

Object A owns an Object B (has a pointer to it)
    When Object A is destroyed, Object B is destroyed too.
Object C has a std::vector of pointers to Object B-s.
    When Object B is destroyed, remove its pointer from Object C's vector.

对象A的生命周期由shared_ptr管理。

它可以完全控制B的生命周期:

struct A {
  std::unique_ptr<B> b;
};

struct A {
  B b;
};

我们将添加observe_B方法:

struct A {
  std::unique_ptr<B> b;
  B* observe_B() { return b.get(); }
  B const* observe_B() const { return b.get(); }
};

我们将逻辑const。对于我们有实际B的情况,我们只是&而不是.get()。因此,我们不再关心如何分配B(指针或A的正文)。

现在我们有一个相对复杂的生命周期请求。明智地使用shared_ptr可能适用于此。实际上,shared_from_this

struct A:std::enable_shared_from_this<A> {
  std::unique_ptr<B> b;
  B* observe_B() { return b.get(); }
  B const* observe_B() const { return b.get(); }

  std::shared_ptr<B const> get_shared_B() const {
    return {shared_from_this(), observe_B()};
  }
  std::shared_ptr<B> get_shared_B() {
    return {shared_from_this(), observe_B()};
  }
};

这里我们使用&#34;别名构造函数&#34;共享指针,用于返回指向非共享对象的共享指针。它的目的正是为了这个目的。我们使用A的共享生命周期语义,但将其应用于B*

C中,我们只存储vector<weak_ptr>

struct C {
  std::vector<std::weak_ptr<B>> m_Bs;
};

现在,当A消失时,weak_ptr到&#34;包含&#34; B失去了最后的强烈参考。当你.lock()时,它现在失败了。

struct C {
  std::vector<std::weak_ptr<B>> m_Bs;
  void tidy_Bs() {
    auto it = std::remove_if( begin(m_Bs), end(m_Bs), [](auto&& x)->bool{return !x.lock();});
    m_Bs.erase(it, end(m_Bs));
  }
};

tidy_Bs删除所有&#34;悬空&#34; weak_ptrBm_Bs。{/ p>

要进行迭代,我通常会这样做:

struct C {
  std::vector<std::weak_ptr<B>> m_Bs;
  void tidy_Bs() {
    auto it = std::remove_if( begin(m_Bs), end(m_Bs), [](auto&& x)->bool{return !x.lock();});
    m_Bs.erase(it, end(m_Bs));
  }

  template<class F>
  void foreach_B(F&& f) {
    tidy_Bs();
    auto tmp = m_Bs;
    for (auto ptr:m_Bs)
      if (auto locked = ptr.lock())
        f(*locked);
  }
};

f向量中的每个仍然存在的B&传递B一个m_Bs。虽然它在那里,但它清理了死者。

我复制了这个向量,因为在迭代时,有人可以去改变m_Bs的内容,并且在发生这种情况时我不能在m_Bs上进行迭代。

可以在A未管理shared_ptr的情况下完成整个技术;但是B必须由shared_ptr管理。

请注意,通常&#34;通常&#34;如果A当前C .lock()包含B AC可能无法实际销毁df['e'] = np.where((df['a'] == 1) & (df['b'] == 1), -1, 1) print (df) a b c e 0 1 1 0 -1 1 1 -1 1 1 2 1 0 0 1 。实际上,除了使SELECT date, eventype, count(*) AS count, (UNIX_TIMESTAMP(date)) DIV 600 AS group_field FROM vpnhistory WHERE partnername REGEXP 'CESAR' GROUP BY group_field; 崩溃之外,没有办法避免这种情况。