为什么一个对象在作为指针传递时超出范围,但在返回时却没有
Why does an object go out of scope when passed as a pointer, but not when it is returned
制作一个非常简单的链表我发现自己对什么可能是一个非常简单的作用域概念感到困惑。第一个按预期工作。似乎在第二个 makeNode 函数中,节点 "n" 在终止时超出范围。我很困惑为什么会这样。
我很确定分配的内存仍然存在,并且两种方法都有一个指向该内存的指针。那么为什么一个不起作用?
程序有两个制作节点的功能
#include <iostream>
using namespace std;
struct Node
{
int value;
Node* next;
Node() : next(NULL){}
};
Node* makeNode1(int value)
{
Node* n = new Node;
n->value = value;
return n;
}
void makeNode2(int value, Node* mountPt)
{
Node* n = new Node;
n->value = value;
mountPt = n;
}
void destroyNode(Node* mountPt)
{
if(mountPt->next != NULL)
{
destroyNode(mountPt->next);
delete mountPt;
}
}
int main() {
Node* origin = NULL;
// This works
origin = makeNode1(4);
// causes a runtime error when dereferenced
makeNode2(4, origin);
return 0;
}
对于makeNode2
指针参数mountPt
本身是按值传递的,那么在函数内部对指针本身的任何修改如mountPt = n;
与原来的无关参数 origin
.
您可以将其更改为按引用传递,即
void makeNode2(int value, Node*& mountPt)
首先,您正在创建一个新的内存部分,并带有指向该内存部分的指针(这只是一个地址),然后返回该地址。第二个示例传入一个指向内存中地址的指针,然后在函数范围内重新分配该地址(即更改该值)。但是,一旦函数退出,该指针(它所指的地址)的值将恢复为之前的调用,因为指针已经在堆栈上有一个值。不同之处在于,在第一次调用中,您更改了存储在最终传出函数的地址中的值,而在第二次调用中,您更改了指针指向的地址,但该指针返回指向旧地址一旦将范围更改回主体。
更改以下功能:
void makeNode2(int value, Node* mountPt)
{
Node* n = new Node;
n->value = value;
if(mountPt) delete mountPt;
mountPt = n;
}
如果 mountPt 已经分配,它将被释放,然后 origin
可以指向分配 n
X-Y 解决方案:通过扩展 Node 构造函数来消除对 makeNode
函数的需求
struct Node
{
int value;
Node* next;
Node(int val = 0) :value(val), next(NULL){}
};
用法
Node * origin = new Node(4);
虽然以上所有内容(包括已接受的答案)都是相关的,但 none 直接指出了实际的逻辑缺陷。您需要 mountPt->next = n;
.
而不是 mountPt = n;
制作一个非常简单的链表我发现自己对什么可能是一个非常简单的作用域概念感到困惑。第一个按预期工作。似乎在第二个 makeNode 函数中,节点 "n" 在终止时超出范围。我很困惑为什么会这样。
我很确定分配的内存仍然存在,并且两种方法都有一个指向该内存的指针。那么为什么一个不起作用?
程序有两个制作节点的功能
#include <iostream>
using namespace std;
struct Node
{
int value;
Node* next;
Node() : next(NULL){}
};
Node* makeNode1(int value)
{
Node* n = new Node;
n->value = value;
return n;
}
void makeNode2(int value, Node* mountPt)
{
Node* n = new Node;
n->value = value;
mountPt = n;
}
void destroyNode(Node* mountPt)
{
if(mountPt->next != NULL)
{
destroyNode(mountPt->next);
delete mountPt;
}
}
int main() {
Node* origin = NULL;
// This works
origin = makeNode1(4);
// causes a runtime error when dereferenced
makeNode2(4, origin);
return 0;
}
对于makeNode2
指针参数mountPt
本身是按值传递的,那么在函数内部对指针本身的任何修改如mountPt = n;
与原来的无关参数 origin
.
您可以将其更改为按引用传递,即
void makeNode2(int value, Node*& mountPt)
首先,您正在创建一个新的内存部分,并带有指向该内存部分的指针(这只是一个地址),然后返回该地址。第二个示例传入一个指向内存中地址的指针,然后在函数范围内重新分配该地址(即更改该值)。但是,一旦函数退出,该指针(它所指的地址)的值将恢复为之前的调用,因为指针已经在堆栈上有一个值。不同之处在于,在第一次调用中,您更改了存储在最终传出函数的地址中的值,而在第二次调用中,您更改了指针指向的地址,但该指针返回指向旧地址一旦将范围更改回主体。
更改以下功能:
void makeNode2(int value, Node* mountPt)
{
Node* n = new Node;
n->value = value;
if(mountPt) delete mountPt;
mountPt = n;
}
如果 mountPt 已经分配,它将被释放,然后 origin
可以指向分配 n
X-Y 解决方案:通过扩展 Node 构造函数来消除对 makeNode
函数的需求
struct Node
{
int value;
Node* next;
Node(int val = 0) :value(val), next(NULL){}
};
用法
Node * origin = new Node(4);
虽然以上所有内容(包括已接受的答案)都是相关的,但 none 直接指出了实际的逻辑缺陷。您需要 mountPt->next = n;
.
mountPt = n;