C++ 引用的std::shared_ptr是否应该在方法超出范围后删除?

C++ 引用的std::shared_ptr是否应该在方法超出范围后删除?,c++,c++11,shared-ptr,smart-pointers,singly-linked-list,C++,C++11,Shared Ptr,Smart Pointers,Singly Linked List,我正在学习智能指针,学习智能指针比在堆上实现简单结构(如链表)更好 我创建了一个链表结构,如下所示 // linked list node definition #ifndef __LINKED_LIST_NODE_H #define __LINKED_LIST_NODE_H class LinkedListNode { friend class LinkedList; public: int m_value; LinkedListNod

我正在学习智能指针,学习智能指针比在堆上实现简单结构(如链表)更好

我创建了一个链表结构,如下所示

// linked list node definition
#ifndef __LINKED_LIST_NODE_H
#define __LINKED_LIST_NODE_H

class LinkedListNode {
    friend class LinkedList;
public:
    int                 m_value;
    LinkedListNode *    m_pNext;
public:
    LinkedListNode();
    LinkedListNode(int);
    LinkedListNode(const LinkedListNode &);
    ~LinkedListNode();
};

#endif

// linked list definition
#ifndef __LINKED_LIST_H
#define __LINKED_LIST_H

class LinkedList {
    LinkedListNode * m_pHead;
    LinkedListNode * m_pTail;
public:
    LinkedList();
    LinkedList(int);
    LinkedList(const LinkedList &);
    ~LinkedList();
    void PrintList() const;
    void AddItem(int);
    void RemoveItem(int);
    LinkedListNode * FindNode(int) const;
    LinkedListNode * FindMin() const;
    LinkedListNode * FindMax() const;
};

#endif
以下是LinkedListNode和LinkedList类所需的方法(构造函数和析构函数),以查看它们的外观(IIRC这些应该是正确的)

//列表节点
LinkedListNode::LinkedListNode()
{
m_值=0;
m_pNext=nullptr;
}
LinkedListNode::LinkedListNode(int值)
{
m_值=值;
m_pNext=nullptr;
}
LinkedListNode::LinkedListNode(常量LinkedListNode和copyNode)
{
m_值=copyNode.m_值;
m_pNext=copyNode.m_pNext;
}
LinkedListNode::~LinkedListNode()
{
//不需要,无需动态分配
}
//链表
LinkedList::LinkedList()
{
m_pHead=nullptr;
m_pTail=m_pHead;
}
LinkedList::LinkedList(int值)
{
std::sharedptrnewnode{newlinkedListNode(value)};
m_pHead=newNode.get();
m_pHead->m_pNext=nullptr;
m_pTail=m_pHead;
}
LinkedList::LinkedList(常量LinkedList和副本列表)
{
if(copyList.m_pHead==nullptr)
{
m_pHead=nullptr;
m_pTail=m_pHead;
}
其他的
{
std::sharedptrnoderesource{newlinkedListNode(*copyList.m_pHead)};
LinkedListNode*tempNode=NodeResource.get();
m_pHead=临时节点;
while(tempNode->m_pNext!=nullptr)
{           
std::sharedptrnodeResourceNext{newlinkedListNode(*tempNode->m_pNext)};
tempNode->m_pNext=NodeResourceNext.get();
tempNode=NodeResourceNext.get();
}
m_pTail=临时节点;
}
}
LinkedList::~LinkedList()
{
//不需要,使用智能指针进行分配
}
现在,LinkedList类包含AddItem方法,其主体如下:

void LinkedList::AddItem(int value)
{
    std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };

    if (m_pHead == nullptr) // linked list is empty
    {
        m_pHead = newNode.get();
        m_pTail = newNode.get();
    }
    else
    {
        m_pTail->m_pNext = newNode.get();
        m_pTail = newNode.get();
    }
}
void LinkedList::AddItem(int值)
{
std::sharedptrnewnode{newlinkedListNode(value)};
如果(m_pHead==nullptr)//链表为空
{
m_pHead=newNode.get();
m_pTail=newNode.get();
}
其他的
{
m_pTail->m_pNext=newNode.get();
m_pTail=newNode.get();
}
}
我不知道为什么,但当我尝试向链接列表中添加一项时,当您超出方法的范围时,newNode变量似乎被删除

下面是我调试程序时的样子

首先我们从空链表开始

然后在AddItem函数中,我得到以下结果(看起来m_pHead和m_pTail正确地指向堆上新创建的newNode)

但是,当AddItem()方法超出范围时,这就是我剩下的

我想,一旦没有任何东西引用指针,std::share_ptr就会被删除。在我的例子中,newNode被两个指针m_pHead和m_pTail引用。它真的是在离开AddItem()方法时被删除的,还是我的代码中有一个我没有发现的缺陷


非常感谢各位的输入。

您正在将
newNode.get()
分配给
LinkedListNode
成员的原始指针(
LinkedListNode*

这是不正确的,因为
共享\u ptr
(在本例中至少)拥有基础指针。当它超出范围时,关联的内存将被释放,但您的
LinkedListNode
仍有以前分配内存的成员


您可能应该更改
LinkedListNode
的定义,以使其
LinkedListNode*
成员是
shared\u ptr
,从而确保只要实例存在,就可以引用底层内存。

您的问题太长了,但我发现您似乎没有在a中使用
std::shared\u ptr
恰当的方式。例如

LinkedList::LinkedList(int value)
{
    std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };
    m_pHead = newNode.get();
    m_pHead->m_pNext = nullptr;
    m_pTail = m_pHead;
}   // <-- call of std::shared_ptr::~std::shared_ptr

但是,您必须小心如何执行插入和切片等操作。

当引用共享ptr的最后一个共享ptr被删除时,共享ptr将被解除分配。它不知道您也在使用常规指针来指向它。您可能认为这些屏幕截图有帮助,但它们实际上是有害的:它清楚地表明您在qu方面付出了一些努力但是这让我们很难回答,因为我们无法复制任何内容,必须重新键入所有内容。@ereOn很抱歉给您带来不便,我不是这个网站的经验丰富的用户。@Andy:不用担心。SO的好处是您可以随时更新/修复您的问题/答案,以造福所有人:)哦,我明白了,所以使用.get()方法od std::shared_ptr实际上没有向变量添加引用?这意味着编译器不知道某些东西实际上指向变量,因此在变量超出范围时将其删除?我理解对了吗?不需要一个
共享的\u ptr
,他只需要做
m\u pHead
m\u pNext
唯一的\u ptr
就可以了fine@RedAlert:很可能,但我们没有足够的上下文来判断是否应该使用
shared\u ptr
unique\u ptr
(据我们所知,其他一些代码可能需要
节点的共享\u ptr
)。尽管如此,选择要使用的智能指针可能不是解决这个问题的第一个问题。顺便说一句,列表实现中的智能指针很可怕-如果列表很大,你会得到非常深的调用堆栈,因为清理是在析构函数中递归完成的。@ereOn我被告知指针不能拥有资源。例如,Object*newObject=new Object();是一种糟糕的做法。有人告诉我,使用智能指针管理堆上的内存是一种更好的方法。这是错误的吗?
std::shared_ptr
asside,你认为使用
std::unique_ptr
可能更好(或唯一可行的方法)吗这种情况下的想法?@Andy在你决定要使用哪种智能指针之前,你需要先有一个一致的所有权模型。你认为谁应该拥有一个
LinkedListNode
LinkedList::LinkedList(int value)
{
    std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };
    m_pHead = newNode.get();
    m_pHead->m_pNext = nullptr;
    m_pTail = m_pHead;
}   // <-- call of std::shared_ptr::~std::shared_ptr
template<typename T> class list;
template<typename T>
class node {
  friend class list<T>;
  T m_data;
  unique_ptr<node> m_next;
  explicit node(T const&value)
  : m_data(value) {}
  node(T const&value, unique_ptr<node>&&n)
  : m_data(value), m_next(n) {}
public:
  node*next() { return m_next.get(); }
  const node*next() const { return m_next.get(); }
};

template<typename T>
class list {
  typedef node<T> node_type;
  unique_ptr<node_type> m_head;
  node_type            *m_tail;
  ~list() {}  // destructor of m_head destroys all nodes recursively
  explicit list(T const&value)
  : m_head(new node_type(value)), m_tail(m_head.get()) {}
  void push(T const&value)
  {
    // move the existing m_head to be m_next of the new node,
    // which in turn becomes the new m_head. m_tail is unaffected.
    m_head = new node_type(value,std::move(m_head));
  }
};