我正在学习智能指针,学习它比在堆上实现简单结构(如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;
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这些应该是正确的)......
// list node
LinkedListNode::LinkedListNode()
{
m_value = 0;
m_pNext = nullptr;
}
LinkedListNode::LinkedListNode(int value)
{
m_value = value;
m_pNext = nullptr;
}
LinkedListNode::LinkedListNode(const LinkedListNode & copyNode)
{
m_value = copyNode.m_value;
m_pNext = copyNode.m_pNext;
}
LinkedListNode::~LinkedListNode()
{
// not needed, no dynamic allocation
}
// linked list
LinkedList::LinkedList()
{
m_pHead = nullptr;
m_pTail = m_pHead;
}
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;
}
LinkedList::LinkedList(const LinkedList & copyList)
{
if (copyList.m_pHead == nullptr)
{
m_pHead = nullptr;
m_pTail = m_pHead;
}
else
{
std::shared_ptr<LinkedListNode>NodeResource{ new LinkedListNode(*copyList.m_pHead) };
LinkedListNode * tempNode = NodeResource.get();
m_pHead = tempNode;
while (tempNode->m_pNext != nullptr)
{
std::shared_ptr<LinkedListNode>NodeResourceNext{ new LinkedListNode(*tempNode->m_pNext) };
tempNode->m_pNext = NodeResourceNext.get();
tempNode = NodeResourceNext.get();
}
m_pTail = tempNode;
}
}
LinkedList::~LinkedList()
{
// not needed, allocating using smart pointers
}
现在,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();
}
}
我不知道为什么,但是当我尝试将一个项目添加到我的链接列表时,当你超出方法的范围时,似乎会删除newNode变量。
以下是我尝试调试程序时的样子......
首先我们从空链表开始
然后在AddItem函数中我得到以下结果(看起来m_pHead和m_pTail正确地指向堆上新创建的newNode。
但是当AddItem()方法超出范围时,这就是我剩下的
我想,一旦没有引用指针,就会删除std :: share_ptr。在我的例子中,newNode由两个指针m_pHead和m_pTail引用。离开AddItem()方法时它是否真的被删除了,或者我的代码中是否有缺陷我还没有被发现?
非常感谢你的意见,伙计们。
答案 0 :(得分:4)
您要将newNode.get()
分配给LinkedListNode*
的原始指针(LinkedListNode
)成员。
这是不正确的,因为shared_ptr
(在这种情况下至少)拥有底层指针。当它超出范围时,相关的内存被释放,但LinkedListNode
仍然拥有以前分配的内存的成员。
您可能应该更改LinkedListNode
的定义,以便其LinkedListNode*
成员为shared_ptr<LinkedListNode>
,确保只要您的实例存在,就会引用基础内存。
答案 1 :(得分:1)
您的问题太长了,但我发现您似乎没有以适当的方式使用std::shared_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
newNode
将在函数体的末尾被销毁。然后,这将删除共享指针的对象(恰好在一个std::shared_ptr
之间),从而使m_pHead
留下悬空指针。
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));
}
};
但是,你必须小心如何实现插入和切片等。