chaining classe in CPP

120 Views Asked by At

The major problem I find at the moment is with "initializing pointers" .

In Pascal, all you had to do is declare NEW(POINTER). In C++, I am lost as - correct me if i am wrong - you have to declare a "dummy" variable in order to initiate a pointer.

Let me put in this way: I want to build a class that will be chained by pointers. In Pascal, all I had to do is add the class a pointer, I called it next, of the same kind that it is nested in.

How do I it in C++?

1

There are 1 best solutions below

3
On

Pointers work exactly the same way in C++ as they do in Pascal. The only difference is in how you allocate and free the things being pointed at.

For instance, you can declare a local variable and point to it, eg:

int i = 12345;
int *p = &i;
// use p as needed...

This would be equivalent to this in Pascal:

var
  i: Integer;
  p: ^Integer;
begin
  i := 12345;
  p := @i;
  // use p as needed...
end;

Or, you can use new and delete to work with variables allocated dynamically, eg:

someType *data = new someType;
// use data as needed ...
delete data;

Which is equivalent to this in Pascal:

type
  someType = record
    ...
  end;

var
  data: ^someType;
begin
  New(data);
  // use data as needed ...
  Dispose(data);
end;

However, modern C++ code should strive to avoid using new/delete directly as much as possible. Use smart pointers instead (std::unique_ptr and std::shared_ptr, via std::make_unique() and std::make_shared()), which free memory automatically when they go out of scope and get destroyed. This helps make code safer and more self-documenting as to the ownership semantics of pointed-at data. Use raw pointers only where needed to access data without transferring ownership of it, eg:

void doSomething(someType *data)
{
    // use data as needed ...
}

{
    auto data = std::make_unique<someType>();
    doSomething(data.get());
} // <-- data is freed automatically here!

The type of class you describe is more formally known as a node/element of a "linked list", which is commonly implemented using new/delete, eg:

#include <iostream>

struct node
{
    int data;
    node* next = nullptr;
};

node *head = nullptr;
node *tail = nullptr;

void addToList(int data)
{
    node **n = (tail) ? &(tail->next) : &head;
    *n = new node{data};
    tail = *n;
}

void clearList()
{
    node *n = head;
    while (n) {
        node *next = n->next;
        delete n;
        n = next;
    }
    head = tail = nullptr;
}

void printList()
{
    node *n = head;
    if (n)
    {
        std::cout << n->data;
        while ((n = n->next) != nullptr) {
            std::cout << ", " << n->data;
        }
    }
    std::cout << std::endl;
}

int main()
{
    addToList(12345);
    addToList(67890);
    printList();
    clearList();
    return 0;
}

A linked-list is not a good example for using smart pointers, though. Yes, the head pointer could be a smart pointer, at least. But you would still have to iterate the list destroying the individual nodes, before the unique_ptr destroys the head node. And you might be tempted to make the next pointers be smart pointers too, but doing that would be a bad idea, as recursive destructor calls can blow up the call stack when destroying large linked-lists. Iterative loops are more suitable for destroying linked-lists, and having next be a smart pointer is not a good fit for that use-case.

But, in any case, C++ has built-in standard classes for double-linked lists (std::list) and single-linked lists (std::forward_list), which handle the linking pointers for you, so you can focus more on your class data and less on how the class instances are linked together, eg:

#include <iostream>
#include <list>

std::list<int> l;

void printList()
{
    auto iter = l.begin();
    if (iter != l.end())
    {
        std::cout << *iter;
        while (++iter != l.end()) {
            std::cout << ", " << *iter;
        }
    }
    std::cout << std::endl;
}

int main()
{
    l.push_back(12345);
    l.push_back(67890);
    printList();
    return 0;
}