×
Get in touch

Get in touch with Binary

Binary Studio website uses cookies to enhance your browsing experience. By continuing to use our site, you agree to our Privacy Policy and use of cookies.

Learn more more arrow
Agree
andrew.kramarenko@binary-studio.com'
Andrew Kramarenko C++ Developer 17.03.2014

Do not muddle references and pointers


.CPP files under the hood with pitfalls!

Introduction

Binary Studio Andrew loves CPP.jpgBeginning with this article I am going to start a set of articles about different things in C++ which can confuse and challenge some junior programmers or be interesting for getting a deeper knowledge about this language. I will try to tell everything in a clear and comprehensible way. Articles will contain a lot C++ code with lots of comments. I usually use GCC compiler with enabled C++11 standard on Linux machine, in case of other environment, I will mention this.

My first message is aimed at the first target group who usually don't deal well with the title. My goal is to describe difference between these fundamental entities and make some kind of guide how to use them with the Force.

 

So what kind of beasts pointers and references are?

or some kind of history

 

History comes first. Pointers are legacy from C-times. I don't use this phrase in negative sense, because it is a very useful acquisition. Pointers provide random access in memory of computer. This means that pointer is an address in the memory. What you can get by this address? Usually it will be your variables or set of variables (arrays).

References appeared in C++ when there was an issue with overloading operators which return type for other operations, such as []. You must remember this correct overloading, but just for one moment let’s think that C++ doesn't have references. It would be like this:

 

and everything is great until you try to assign returned value:

OK, then you can write something like this with pointers:

and it works in the following way:

but when you see this, you think "uugh, it is ugly!". We are forced to use dereference operator *. Also it collapses encapsulation of class, because we get raw pointer and nobody forbids to use it and modify any values in its memory space. We can do such tricks:

very bad boy, very bad...

So there is a typical situation where we need good l-value for operator [] which we can change without collapsing encapsulation of the class. References are what we need. Meet:

Perfect! It works, it is elegant and it doesn't hurt anybody, but we still don't know what reference is.

Actually it is dereferenced constant pointer. That means we still get object by address, we can modify object, but address itself can't be modified. In simple words it is a nice way to hide ugly constructions with pointers and their dereference operator from us.

 

Main difference

or understand everything

 

Lets see how we create pointers for different purpose:

in order of appearance:

(1.1) We use operator new to create integer object whose value is 10 and we must use operator delete to free it (1.5)

(1.2) We use operator new [] to create a set of integer objects. Set has size 1 and single object has value 10. In such cases do not forget to free memory with operator delete [] (1.6)

(1.3) We use operator & which takes address of the variable (do not muddle it with declaration of reference!). We don't free this pointer, because it is addressed to variable on stack which destroys when performing of code is gone out of scope.

(1.4) We address pointer on nullptr which means that nothing was allocated and there is nothing to free. There is just silence and nirvana.

Let’s see how we create references

Actually (2.1), (2.2) and (2.3) are very similar, but used in different context. We get reference on already existing variable:

(2.1) is local variable;

(2.2) is argument of function which is pointer;

(2.3) is argument of function passed by value.

If you take a look at (1.4) and (2.*) little bit more, than you get first difference between pointers and references: references have to be addressed somewhere, but pointers aren’t. It means following code doesn't compile:

but this does:

OK you can ask about such case:

I want to ask counter question – who is your doctor? Never act like this and you will be blessed. It isn't an issue of reference. It is an issue of dereferencing of nullptr, because by standard this is undefined behavior. Any compiler doesn't guarantee correct work here.

Take a look at (1.2) and (2.*) again. See? - References is addressed to single object.

Next: references can't be addressed to other object after its creation. Following code proves it:

If you return to implementation of operator [] which returns pointer, you may understand: references don't support address arithmetic. You will never see code with references which use operator +, operator -, operator – or operator ++ for changing address. Only pointers can do this and that's why C or C++ is usually called low level language when it comes to memory management.

 

When do we usually use them with Force?

or typical use cases

 

For what purpose pointer can be used:

  • we want to allocate an object and deliver its lifetime management to another place;
  • we want to hold set(massive, array) of objects on heap;
  • we want to pass argument in function\method which can be nullptr (NULL before C++11) (do not forget to check on it!);
  • we want to use class field with postponed initialization;

For what purpose reference can be used:

  • we want to pass in function\method argument which is always initialized and we don't want to spend time on copying it how it does on passing by value;
  • we want to hold in class field which is initialized, but in other place;
  • we want to return some field from class without copying its data.

And last one, don't worry - polymorphism works well on both entities.

 

Conclusion

That's all what I wanted to say. There are some phrases which make up a summary of the article:

  • pointers and references is one of the most powerful and basic entities of C++ world;
  • they are different;
  • use cases are different;
  • each use case provides different, but fast code;
  • reference is safer than pointer;
  • pointer is more flexible than reference.

For source code you can visit this github repository.