【问题标题】:Smart pointers and cyclic/noncyclic lists智能指针和循环/非循环列表
【发布时间】:2021-10-10 05:42:11
【问题描述】:

首先我对两个列表都只使用 shared_ptr:

struct Elem {
    string cargo;
    shared_ptr<Elem> next;
    Elem(string cargo) {
        this->cargo = cargo;
    }
    ~Elem() {
        cout << "delete Elem " << cargo << endl;
    }
};

static shared_ptr<Elem> make3nonCyclic() {
    shared_ptr<Elem> A(new Elem("A"));
    shared_ptr<Elem> B(new Elem("B"));
    shared_ptr<Elem> C(new Elem("C"));
    A->next = B;
    B->next = C;
    return A;
}


static shared_ptr<Elem> make3cyclic() {
    shared_ptr<Elem> A(new Elem("A"));
    shared_ptr<Elem> B(new Elem("B"));
    shared_ptr<Elem> C(new Elem("C"));
    A->next = B;
    B->next = C;
    C->next = A;
    return A;
}

static void test2() {
    //non cyclic list of three
    shared_ptr<Elem> head = make3nonCyclic();
    head = head->next;
    cout << "elem A should be deleeted" << endl;
}

static void test3() {
    //cyclic list of three
    shared_ptr<Elem> head = make3cyclic();
    head = head->next;
    cout << "elem A should not be deleeted" << endl;
}

对于非循环列表工作正常,(除了调用递归而不是尾迭代) 对于循环,不释放。 我试过了

  • 更改weak_ptr 旁边的字段:发布太早了
  • 将make3cyclic 中的返回类型和test3 中的head 更改为weak_ptr:不释放。 这个样品怎么做?还有更复杂的:
struct Node {
    shared_ptr<Node> parent;
    Node(shared_ptr<Node> parent) {
        this->parent = parent;
        if (parent!=nullptr)
            depth = parent->depth+1;
    }
    int depth = 0;
    vector<shared_ptr<Node>> children;
    shared_ptr<Node> addChild(shared_ptr<Node> parent) {
        shared_ptr<Node> child(new Node(parent));
        children.push_back(child);
        return child;
    }
};

在“weak_ptr 如何工作?”我可以看到: "当“使用计数”达到零时,指针被删除。

当“弱计数”达到零(这意味着“使用计数”也必须为零,见上文)时,“计数器”辅助对象被删除。”

我认为指针对象和计数器对象密切相关,如果释放计数器对象,指针对象就不能存在。

【问题讨论】:

  • 关于列表的第一课是,如果将 listsnodes 分开,处理起来会变得简单得多。
  • 至于你的问题,你永远不会切断到A 节点的所有连接,你仍然有一个到它的链接(来自C 节点)。如果你想从列表中删除一个节点,你需要更新 all 指向它的指针(C 应该指向 B)。
  • 是的,但是如果 A、B、C 和 head 超出范围,则应该释放整个循环列表。从 C 到 A 的链接应该很弱?但字段 C.next 与 A.next 和 B.next 的类型相同。
  • whole cyclic list should be freed 如果是循环,则不会释放任何内容,因为每个共享指针仍然有一个用户,即循环中的前一个元素。你必须打破循环。
  • 通过设置 head.next = nullptr ?

标签: c++ smart-pointers


【解决方案1】:

make3cyclic()函数创建的列表(即循环列表)的情况下,对象不会释放,因为没有一个对象的对象引用计数达到0。

make3cyclic() 函数中每个对象的引用计数以及函数 test3()head = head-&gt;next; 行之前的引用计数为 2,如下图所示:

在函数test3() 中的head = head-&gt;next; 行之后,对象BC 的引用计数为2,但对于对象A,它仍然是1(而不是你会想到的0),如解释在下图中:

如果要释放内存,则应在 head = head-&gt;next; 行之后添加一行 head-&gt;next-&gt;next = nullptr;,如下所示。 See it working here:

static void test3()
{
    //cyclic list of three
    shared_ptr<Elem> head = make3cyclic();
    head = head->next;
    head->next->next = nullptr;
    cout << "elem A should be deleted now" << endl;
}

对于您的复杂场景,您可以执行以下操作(注意:我添加了 _key 成员只是为了显示有意义的对象破坏日志)。 See in action here:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

struct Node 
{
    weak_ptr<Node> parent;
    char _key;
    int depth = 0;
    vector<shared_ptr<Node>> children;
    
    Node(shared_ptr<Node> parent, const char key) : _key(key)
    {
        this->parent = parent;
        if ( parent )
            depth = parent->depth+1;
    }
    
    ~Node() 
    {
        cout << "delete Node [" << _key << " | " << depth << "]\n";
    }
    
    shared_ptr<Node> addChild( shared_ptr<Node> parent, const char key )
    {
        shared_ptr<Node> child = make_shared<Node>(parent, key);
        children.push_back(child);
        return child;
    }
};


int main() 
{
    auto p = weak_ptr<Node>();
    shared_ptr<Node> root = make_shared<Node>( nullptr, 'A' );
    auto b = root->addChild( root, 'B' );
    root->addChild( root, 'C' );
    root->addChild( root, 'D' );
    b->addChild( b, 'E' );
    auto f = b->addChild( b, 'F' );
    b->addChild( b, 'G' );
    f->addChild( f, 'H' );
    f->addChild( f, 'I' );
    f->addChild( f, 'J' );
    root = nullptr;
    return 0;
}

【讨论】:

    猜你喜欢
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多