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));
}
};