Почему объект выходит из области видимости, когда передается как указатель, а не когда он возвращается - PullRequest
2 голосов
/ 29 марта 2019

Составляя очень простой связанный список, я запутался в том, что, вероятно, является очень простой концепцией области видимости.Первый работает как положено.Казалось бы, во второй функции makeNode узел "n" выходит из области видимости при завершении.Я запутался, почему это происходит.

Я почти уверен, что выделенная память все еще там, и оба метода имеют указатель на эту память.Так почему же один из них не работает?

Программа имеет две функции make node

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

Ответы [ 5 ]

2 голосов
/ 29 марта 2019

Для makeNode2 параметр указателя mountPt сам передается по значению, тогда любая модификация самого указателя внутри функции, такая как mountPt = n;, не имеет ничего общего с исходным аргументом origin.

Вы можете изменить его на переход по ссылке, т.е.

void makeNode2(int value, Node*& mountPt)
1 голос
/ 29 марта 2019

В первом случае вы создаете новый раздел памяти с указателем на этот раздел памяти (который является просто адресом), а затем возвращаете этот адрес. Второй пример передает указатель на адрес в памяти, а затем переназначает этот адрес (то есть изменяет это значение) в области действия функции. Однако значение этого указателя (адрес, на который он ссылается) возвращается к своему предыдущему вызову после выхода из функции, так как указатель уже имеет значение в стеке. Разница в том, что при первом вызове вы меняете значение, сохраненное в адресе, который в конечном итоге передается из функции, а во втором вы меняете адрес, на который указывает указатель, но этот указатель возвращается к указанию на старый адрес. как только вы измените область видимости обратно к основному телу.

0 голосов
/ 29 марта 2019

Хотя все вышеизложенное, включая принятый ответ, имеет значение, ни одно из них не указывает на фактический логический недостаток.Вместо mountPt = n; вам нужно mountPt->next = n;.

0 голосов
/ 29 марта 2019
Решение

X-Y: устраните необходимость в функции makeNode, расширив конструктор Node

struct Node
{
    int value;
    Node* next;
    Node(int val = 0) :value(val), next(NULL){}
};

Использование

Node * origin = new Node(4);
0 голосов
/ 29 марта 2019

Измените функцию для следующего:

void makeNode2(int value, Node* mountPt)
{
    Node* n = new Node;
    n->value = value;
    if(mountPt) delete mountPt;
    mountPt = n;
}

где, если mountPt уже был выделен, он будет освобожден, и тогда origin может указывать на выделение n

...