2

I'm going through a C++ book at the moment and i'm slightly confused about pointing to classes.

Earlier in the book the examples used classes and methods in this way:

Calculator myCalc;
myCalc.launch();

while( myCalc.run() ){
    myCalc.readInput();
    myCalc.writeOutput();
}

However, now it's changed to doing it this way:

Calculator* myCalc = new Calculator;
myCalc -> launch();

while( myCalc -> run() ){
    myCalc -> readInput();
    myCalc -> writeOutput();
}

And I can't seem to find an explanation in there as to WHY it is doing it this way.

Why would I want to point to a class in this way, rather than use the standard way of doing it?

What is the difference? And what circumstances would one or the other be preferable?

Thank you.

Jonas Schäfer
  • 20,140
  • 5
  • 55
  • 69

7 Answers7

9

First, you are not pointing to the class, but to an instance of the class, also called an object. (Pointing to classes is not possible in C++, one of its flaws if you'd ask me).

The difference is the place where the object is allocated. When you're doing:

Calculator myCalc;

The whole object is created on the stack. The stack is the storage for local variables, nested calls and so on, and is often limited to 1 MB or lower. On the other hand, allocations on the stack are faster, as no memory manager call is involved.

When you do:

Calculator *myCalc;

Not much happens, except that a Pointer is allocated on the stack. A pointer is usually 4 or 8 bytes in size (32bit vs. 64bit architectures) and only holds a memory address. You have to allocate an object and make the pointer point to it by doing something like:

myCalc = new Calculator;

which can also be combined into one line like shown in your example. Here, the object is allocated on the heap, which is approximately as large as your phyiscal memory (leaving swap space and architectural limitations unconsidered), so you can store way more data there. But it is slower, as the memory manager needs to kick in and find a spare place on the heap for your object or even needs to get more memory from the operating system. Now the pointer myCalc contains the memory address of the object, so it can be used with the * and the -> operators.

Also you cannot pass pointers or references to objects on the stack outside their scope, as the stack will get cleaned when the scope ends (i.e. at the end of a function for example), thus the object becomes unavailable.

Oh and nearly forgot to mention. Objects on the heap are not automatically destroyed, so you have to delete them manually like this*:

delete myCalc;

So to sum it up: For small, short living objects which are not to leave their scope, you can use stack based allocation, while for larger, long living objects the heap is usually the better place to go.


*: Well, ideally, not like that. Use a smart pointer, like std::unique_ptr.

Jonas Schäfer
  • 20,140
  • 5
  • 55
  • 69
1

Both are standard. One is not preferred over the other.

The first one is typical of local variables that you declare and use in a narrow scope.

The pointer method allows you to dynamically allocate memory and assign it to a pointer type; that's what the "star" notation means. These can be passed out of a method or assigned to a member variable, living on after a method is exited.

But you have to be aware that you are also responsible for cleaning up that memory when you're done with the object the pointer refers to. If you don't, you many eventually exhaust a long-running application with a "memory leak".

duffymo
  • 305,152
  • 44
  • 369
  • 561
1

You use the dot (.) when your variable is an instance or reference of the class while you use -> if your variable is a pointer to an instance of a class.

JohnP
  • 677
  • 1
  • 9
  • 18
1

They are both part of the C++ standard, but there is a core difference. In the first way, your object lives on the stack (which is where functions and local variables are stored, and removed after they are no longer used). When you instead declare your variable type as a pointer, you are only storing a pointer on the stack, and the object itself is going on the heap.

While when you use the stack local variable to allocate the memory, it is automatically taken care of by C++. When it's on the heap, you have to get the memory with new and free it with delete.

While in the stack example your code uses . to call methods, to call methods on a pointer, C++ provides a shortcut: ->, which is equivalent to *obj.method().

Remember, when you use new, always use delete.

Community
  • 1
  • 1
Linuxios
  • 34,849
  • 13
  • 91
  • 116
0

One use would be if the variable myCalc has a very long lifetime. You can create it when you need if with new and remove it when done with delete. Then you don't have to worry about carrying it around at times when it's not needed and would only take up space. Or you can reinitialise it at will when needed, etc.

Or when you have a very big class, it's common practice to use new to allocate it on the heap rather than the stack. This is a leftover from the days when stack space was scarce and the heap was larger, so heap space was cheaper.

Or, of course, the most common use, allocating a dynamic array. myCalc = new Calculator[x]; to create x new calculators. You can't do this with static variables if you don't know beforehand how large x is; how many objects you're going to create.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
0

Other than the obvious difference in notation/syntax. Pointers are generally useful when passing data into a function.

void myFunc(Calculator *c) {
    ...
}

is usually preferred over

void myFunc(Calculator c) {
    ...
}

since the second requires a copy be made of the calculator. A pointer only contains the location to what is being pointed to, so it only refers to another spot in memory instead of containing the data itself. Another good use is for strings, imagine reading a text file and calling functions to process the text, each function would make a copy of the string if it were not a pointer. A pointer is either 4 or 8 bytes depending on the machines architecture so it can save a lot of time and memory when passing it to functions.

In some case though it may be better to work with a copy. Maybe you just want to return an altered version like so

Calculator myFunc(Calculator c) {
    ...
}

one of the important things about pointers is the "new" keyword. It is not the only way to create a pointer but it is the easiest way that for c++. You should also be able to use a function called malloc() but that is more for structs and c IMO but I have seen both ways.

Speaking of C. Pointers may also be good for arrays. I think you can still only declare the size of an array at compile time in c++ too, but I could be mistaken. You could use the following I believe

Calculator *c;
....
Calculator d = c[index];

So now you have an array which can make it quite ambiguous IMO.

I think that covers just about all I know and in the example provided I do not think there is any difference between the two snippets you provided.

mashumafi
  • 5
  • 4
0

First of all, you are not pointing to a class, you are pointing to an instance (or object) of that class. In some other languages, classes are actually objects too :-)

The example is just that, an example. Most likely you wouldn't use pointers there.

Now, what IS a pointer? A pointer is just a tiny little thing that points to the real thing. Like the nametag on a doorbell -- it shows your name, but it's not actually you. However, because it is not you, you can actually have multiple buttons with your name on it in different locations.

This is one reason for using pointers: if you have one object, but you want to keep pointers to that object in various places. I mean, the real world has tons of "pointers" to you in all sorts of places; it shouldn't be too difficult to imagine that programs might need similar things inside their data.

Pointers are also used to avoid having to copy the object around, which can be an expensive operation. Passing a pointer to functions is much cheaper. Plus, it allows functions to modify the object (note that technically, C++ "references" are pointers as well, it's just a little less obvious and they are more limited).

In addition, objects allocated with "new" will stay around until they are deallocated with "delete". Thus, they don't depend on scoping -- they don't disappear when the function around them finishes, they only disappear when they are told to get lost.

Plus, how would you make a "bag with fruit"? You allocate a "bag" object. Then you allocate a "fruit" object, and you set a pointer inside the bag object to point to the fruit object, indicating that the bag is supposed to contain that fruit. The fruit might also get a pointer to the bag object, just so code working on the fruit can also get to the bag. You can also allocate another "fruit" object, and establish a chain of pointers: each "fruit" could have a single "next" pointer that points to the "next" fruit, so you can put an arbitrary number of fruits into the bag: the bag contains a pointer to the first fruit, and each fruit contains a pointer to another fruit. So you get a whole chain of fruits. ( This is a simple "container"; there are several such classes that "contain" an arbitrary number of objects ).

It's actually not that simple to come up with descriptions of when or why pointers are used; usually there'll just be situations where you'll need them. It's much easier to see their usefulness when you run into such a situation. Like "why is an umbrella useful" -- once you step into the pouring rain outside, the usefulness of an umbrella will become obvious.

Christian Stieber
  • 9,954
  • 24
  • 23