我正在尝试使用链接列表的概念创建一个List类,虽然我最初使用的是C ++标准new
关键字,但我决定将其切换为C ++ 11 {{1 }}。但是,当使用智能指针时,我无法使程序正常运行,因为它崩溃了。以下是更改前的一些代码:
std::shared_ptr
这就是变化的样子:
class List
{
public:
void push_back(...) {
Node *temp = new Node;
...
if (!head) {
head = temp;
return;
}
else {
Node *last = head;
...
last->next = temp;
}
}
...
private:
Node *head = nullptr;
};
我觉得问题可能是class List
{
public:
void push_back(...) {
std::shared_ptr<Node> temp(new Node);
...
if (!head) {
head = temp.get();
return;
}
else {
Node *last = head;
...
last->next = temp.get();
}
}
...
private:
Node *head = nullptr; // don't need this to be a smart ptr
};
和head
没有动态分配,也许他们需要使用last
,但我不确定。我究竟做错了什么,我该如何解决?我真的希望这不是重复,因为我似乎无法找到解决我问题的任何东西。感谢。
编辑:
这是shared_ptr
结构:
Node
答案 0 :(得分:4)
首先拥有std::shared_ptr
的原因是让std::shared_ptr
获得指针的完整和完全所有权,并使std::shared_ptr
对{delete
负责1}},一旦指针的最后一个引用消失了。这就是std::shared_ptr
的全部内容。
这意味着一旦将指针放入std::shared_ptr
,std::shared_ptr
现在就完全负责管理指针。它完全拥有它。
因此,将指针放入std::shared_ptr
......然后立即取出它是没有意义的:
head = temp.get();
get()
功能存在原因,但这不是其中之一。
为了正确使用std::shared_ptr
,所有内容都必须为std::shared_ptr
。 head
必须是std::shared_ptr
:
std::shared_ptr<Node> head; // yes, it does need to be a smart ptr
为什么需要std::shared_ptr
?好吧,如果不是,你认为这会发生什么:
std::shared_ptr<Node> temp(new Node);
具体来说,当这个temp
智能指针被销毁时,此函数何时返回?好吧,因为它将是引用此std::shared_ptr
的最后一个Node
,所以很高兴delete
它。您事先get()
并将其置于head
这一事实并不重要。现在,您有head
指向delete
d节点。随之欢闹。
这就是为什么一切都必须是std::shared_ptr
。不仅head
,而且Node
next
成员 也需要成为std::shared_ptr
也是。
现在,有一个涉及循环引用的陷阱,当std::shared_ptr
进入图片时会发挥作用。但这将成为一个不同的问题。
答案 1 :(得分:1)
您的主要问题是,如果您要使用shared_ptr
,最好一直使用它。将next
设为shared_ptr
而不是原始。{/ p>
struct Node {
int data;
std::shared_ptr<Node> next;
}
引擎盖下的std::shared_ptr
所做的是保持对指针的引用数量的计数。当您使用复制构造函数或operator=
时,它会增加引用计数。当一个实例超出范围导致析构函数被调用(或者你给它一个带有operator=
的不同指针)时,引用计数会减少。当计数为零时,指针被销毁。
// pass by value invokes copy constructor (refcount + 1)
void myFunc(std::shared_ptr<MyClass> var) {
// Code using var
} // end of function invokes destructor (refcount - 1)
void run() {
std::shared_ptr<MyClass> ptr(new MyClass); // refcount = 1
myFunc(ptr); // refcount = 2
// After myFunc returns refcount = 1
}
int main() {
run(); // refcount = 1
// After run returns, refcount = 0 and the pointer is deleted
}
通过使用get()
,您可以引入一个指向内存的指针,该指针可能会在某个时刻被删除,无论该指针是否在周围。这可能导致段错误,因为原始指针指向shared_ptr
删除的内存。
这是因为get()
不会影响引用计数。怎么可能呢?它不再是shared_ptr
,因此类定义无法知道您使用它做什么,或者何时被删除。如果get()
增加了引用计数,那么之后就没有什么可以减少它,并且永远不会释放内存。这是内存泄漏!