从弱指针创建共享指针是安全/不好的做法

时间:2018-11-05 16:50:15

标签: c++ shared-ptr circular-dependency weak-ptr

简介

我有两个班级,在这里分别称为NodePoint。点是持有特定信息的对象(这些信息完全无关紧要,在示例中我使用一个简单的整数)。节点是管理多个点(如果它们应该共享相同的信息)的对象。因此,Node包含指向其管理的所有点的指针的列表(这很好,因为Point如果其生命周期结束,则将从节点中删除其引用),并且每个点都有对节点本身的反向引用。这将创建一个循环引用,这会使事情变得有些棘手。我不使用多线程,因此无需考虑任何种族。另外,我必须使用C ++ 03(基本上是C ++ 98)并提升1.53,所以我可以使用的功能存在局限性。

编辑:

似乎还不清楚,我想补充一点,这实际上是对实际代码的非常简单的提取。因为我想提供一个最小的工作示例,所以我尽力从原始程序中提取功能。但是,请确保在实际程序中必须使用共享指针,因为这些资源在具有不同类的多个对象之间共享。我也使用共享指针,因为它们始终是可选的,这意味着您可以检查它们是否为NULL,如果未分配它们,则可以采取不同的操作,如下面的代码所示。

问题

我还没有进一步描述“对节点的反向引用”,因为这是问题开始的地方。因此,目前我决定采用以下解决方案:

我的Node包含一个指向自身的弱指针,因此可以将所有权共享给其他点。在添加点时,节点从像这样的弱指针创建共享指针

p->node = this->weakThis.lock();

但是我不知道这是不好的做法还是存在严重的问题,这些问题我看不到,因为对weak_ptr::lock()的引用仅说明尽管名称混乱,它还是创建了一个新的共享库,或者这是可接受的代码。

我想到的其他解决方案

  • 所有类均获得共享指针

    • 好:无需从弱对象创建共享对象
    • 不好:需要显式删除类内的共享对象(例如调用方法Node::destroySelfReference(),这很容易被遗忘。否则,该对象可以通过引用自身而永远存在。< / li>
  • 所有类都获得弱指针

    • 好:我们只需要复制弱指针而不共享所有权
    • 不好:每次我们要从调用lock()的那一点开始访问该节点。而且,由于Point中的引用并未真正用作观察者,而是像共享引用一样使用,因此已过时。

问题

什么是最好的解决方案?他们的真正危险是什么?

代码

/* Using boost 1.53 */
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/weak_ptr.hpp>

using boost::shared_ptr;
using boost::make_shared;
using boost::weak_ptr;
using std::cout;
using std::endl;

/*-------------Classes-----------*/

class Point;

class Node {
private:
    std::vector<Point *> points;
    weak_ptr<Node> weakThis;
public:
    int value;
    Node(Point * p, shared_ptr<Node> & sp);
    void add(Point * p);
    void remove(Point * p);
    int getValue() {
        return this->value;
    }
};

class Point {
private:
    int value;
public:
    shared_ptr<Node> node;
    Point() : value(2) {}
    ~Point() {
        if(this->node != NULL) {
            this->node->remove(this);
        }
    }
    int getValue() {
        if (this->node == NULL) return this->value;
        else {
            return this->node->getValue();
        }
    }
};

/*----------Node definition------------*/

Node::Node(Point * p, shared_ptr<Node> & sp) : value(1) {
    sp.reset(this);
    this->weakThis = sp;
    this->add(p);
}

void Node::add(Point * p) {
    this->points.push_back(p); /* simplified without checking if element exists since it is unnecessary for the problem */
    p->node = this->weakThis.lock(); /* <- critical part */
}

void Node::remove(Point * p) {
    std::vector<Point *>::iterator it = std::find(this->points.begin(), this->points.end(), p);
    if (it != this->points.end()) {
        Point * pr = *it;
        this->points.erase(it);
        pr->node.reset();
    }
}

/*------------main-----------*/

int main() {
    Point p;
    cout << "Value of unmanaged p is " << p.getValue() << endl;
    shared_ptr<Node> n;
    new Node(&p, n); /* This is a bit strange too but other creations will not work */
    cout << "Added p to n" << endl;
    cout << "Value of managed p is " << p.getValue() << endl;

    n->remove(&p);
    n.reset();
    return 0;
}

0 个答案:

没有答案