2010-10-07 3 views
0

Это вопрос noobie, но я не уверен, как пройти по ссылке в C++. У меня есть следующий класс, который устанавливает узел и несколько функций.Передача объекта по ссылке в C++

class Node 
{ 
    public: 
    Node *next; 
    int data; 
    Node(int dat) 
    { 
     next = NULL; 
     data = dat; 
    } 
    Node* getNext() 
    { return next; } 
    void setNext(Node *n) 
    { next = n;} 

    void reverse(Node *root) 
    { 
     Node *previous = NULL; 
     while(root != NULL) 
     { 
     Node *next = root->getNext(); 
     root->setNext(previous); 
     previous = root; 
     root = next; 
     } 
     root = previous; 
    } 
}; 

Теперь целью моего маленького класса является создание уникально связанного списка и возможность его отменить. И, похоже, он работает нормально, если я верну узел с именем «предыдущий» в конце обратного.

Но посмотрите на мою основную функцию:

int main() 
{ 
    Node *root = new Node(1); 
    Node *num2 = new Node(2); 
    Node *num3 = new Node(3); 
    Node *num4 = new Node(4); 

    root->setNext(num2); 
    num2->setNext(num3); 
    num3->setNext(num4); 
    root->printList(); 
    root->reverse(root); 
    root->printList(); 

    return 0; 
} 

перечень печати() было опущено для пространства, но он просто выводит список данный узел. Проблема в том, что когда root-> reverse (root) вызывается, root фактически не указывает на «предыдущий».

Выход будет таким:

1 
2 
3 
4 
    // the value of previous from the reverse function is 4 
1 

Я действительно не понимаю, выход. Кто-нибудь хочет объяснить, что происходит? (Почему нет списка в обратном порядке, хотя если бы я сделал что-то вроде этого root = root-> reverse (root), где обратное возвращает предыдущее, это было бы), почему он теперь root указывает только на себя? Я новичок в C++ и ценю вашу помощь!

+0

Следует упомянуть, что эта программа выполняет утечку памяти, поскольку управление ресурсами C++ (т.е. RAII) обходит. – Arafangion

+0

Я действительно мало знаю об управлении на С ++, расскажу, где это утечка памяти, и, может быть, как я могу это исправить? Я знаю, что мне нужно просто прочитать документы, но пример такого реального мира может помочь разжечь огонь :) – kodai

+1

В принципе, если вы вызываете новое, вам нужно самому управлять памятью, а это значит, что вы вызываете delete. Каждое новое должно иметь соответствующее удаление. Не использовать новый (т. Е. Просто делать «Foo foo», а не «Foo * foo = new Foo()»), значит, вы можете позволить C++ управлять этим ресурсом для вас, и вам не нужно беспокоиться об его удалении. (Infact, это ошибка). – Arafangion

ответ

3

C++ поддерживает ссылочную семантику. Таким образом, для данной функции:

void foo(Bar& bar); 

Чтобы пройти по ссылке вы:

int main() { 
    Bar whatsit; 

    foo(whatsit); 

    return 0; 
} 

Вот оно!

Это обычно путают с передаете указатель, где для функции, такие как:

void foo(Bar* bar); 

Вы бы сделать:

int main() { 
    Bar whatisit; 

    foo(&whatsit); 

    return 0; 
} 

Разница заключается в основном вопрос семантики: - A ссылка всегда действительна. Нет причин проверять указатель NULL. - Указатель может быть NULL и должен быть проверен.

Однако, если ссылка ссылается на указатель NULL, если программист решает быть злым и злоупотреблять ссылочной семантикой, но принцип остается.

+0

Итак, я думаю, что понимаю, что вы, ребята, означаете, что передаете по значению копию указателя. Тогда я понимаю, почему работает обратное (Node * и root). Я все еще не уверен, почему что-то вроде: reverse (Node & root) будет работать. Я попробовал, и он не будет компилироваться. Связано ли это с тем, как Рут объявляется и называется? (Node * root = new Node (1); root-> reverse (root)) – kodai

+1

Там root является указателем на узел. Это не ссылка. – Arafangion

+1

Изменение параметра на (Node & root) заставляет функцию ожидать передачи Узла. Для этого, в основном, вы либо захотите удалить указатели, либо просто сделать Nodes (например, «Node root;»), вызывая функцию типа reverse (root) или сохраняя указатель и передавая фактический узел, указатель указывает, как обратный (* корень). –

2

Чтобы передать указатель по ссылке вы можете объявить reverse как:

void reverse(Node*& root) { 
    // ... 
} 
3

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

Причина, по которой возвращается/назначает указатель, заключается в том, что эта копия, которая была настроена на то, что вы хотите, возвращается и назначается вашему указателю в основном.

Вы можете исправить это множеством способов. Передайте ссылку на ваш указатель (уродливое imo), используйте ссылки или верните корень и выполните задание.

Смежные вопросы