提问人:mreff555 提问时间:3/29/2019 最后编辑:songyuanyaomreff555 更新时间:3/29/2019 访问量:1267
为什么对象在作为指针传递时超出范围,但在返回时却没有
Why does an object go out of scope when passed as a pointer, but not when it is returned
问:
制作一个非常简单的链表时,我发现自己对可能是一个非常简单的范围界定概念感到困惑。第一个按预期工作。似乎在第二个 makeNode 函数中,节点“n”在终止时超出了范围。我很困惑为什么会这样。
我很确定分配的内存仍然存在,并且这两种方法都有一个指向该内存的指针。那么为什么一个不起作用呢?
该程序有两个 make 节点函数
#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;
}
答:
3赞
songyuanyao
3/29/2019
#1
对于指针参数本身是按值传递的,那么函数内对指针本身的任何修改都与原始参数无关。makeNode2
mountPt
mountPt = n;
origin
您可以将其更改为按引用传递,即
void makeNode2(int value, Node*& mountPt)
评论
0赞
ShadowRanger
3/29/2019
请注意,这样做会导致内存泄漏;分配的原始指针将替换为分配的新指针,而不使用 -ed。origin
makeNode1
makeNode2
delete
0赞
mreff555
3/29/2019
我知道。显然只需要一个函数。我只是简单地展示了这两种配置。
1赞
CodeoftheWarrior
3/29/2019
#2
首先,您创建一个新的内存部分,其中包含指向该内存部分(只是一个地址)的指针,然后返回该地址。第二个示例将指针传递到内存中的地址,然后在函数的作用域中重新分配该地址(即更改该值)。但是,一旦函数退出,该指针的值(它引用的地址)就会恢复到其之前的调用,因为指针在堆栈上已经有一个值。区别在于,在第一次调用中,您更改了存储在最终从函数中传出的地址中的值,而在第二次调用中,您更改了指针指向的地址,但是一旦将作用域更改回主体,该指针就会返回指向旧地址。
评论
0赞
CodeoftheWarrior
3/29/2019
按值传递指针仍允许您永久更改存储在某个地址的值,但不允许更改指针指向的内容。
0赞
user4581301
3/29/2019
“恢复”是一种糟糕的描述方式。源永远不会改变。
0赞
Vuwox
3/29/2019
#3
更改以下功能:
void makeNode2(int value, Node* mountPt)
{
Node* n = new Node;
n->value = value;
if(mountPt) delete mountPt;
mountPt = n;
}
如果 mountPt 已经分配,它将被释放,然后可以指向分配origin
n
评论
0赞
mreff555
3/29/2019
我同意这将是更好的内存管理,但这不会有同样的范围问题吗?
0赞
user4581301
3/29/2019
@mreff555 是的,它会的。
0赞
mreff555
3/29/2019
实际上没有。但是,如果将引用运算符附加到 Node* 参数中,如上所述,则它可以工作
0赞
user4581301
3/29/2019
#4
X-Y 解决方案:通过扩展 Node 构造函数来消除对函数的需求makeNode
struct Node
{
int value;
Node* next;
Node(int val = 0) :value(val), next(NULL){}
};
用法
Node * origin = new Node(4);
0赞
Red.Wave
3/29/2019
#5
虽然以上所有内容(包括公认的答案)都是相关的,但没有一个直接指向实际的逻辑缺陷。而不是 ,您需要 。mountPt = n;
mountPt->next = n;
评论
makeNode2
makeNode2
if(mountPt) delete mountPt;
n
parameter 'mountPt' set but not used