Android,iOS,Gadgets,Reviews Everything About Technology

Pointers in C ++: why are they needed, when to use and how are they different from accessing the object directly

231

Even if most programmers understand the difference between objects and pointers to them, sometimes it’s not entirely clear what type of approach to the object is worth making a choice. Below we tried to answer this question.

Question

- Advertisement -

I noticed that often programmers, whose code I saw, use pointers to objects more often than these objects themselves, ie, for example, use the following construction:

Object *myObject = new Object;

instead:

Object myObject;

Similarly with methods. Why instead:

myObject.testFunc();

we must write this:

myObject->testFunc();

I understand that this gives a gain in speed, because we address directly to memory. Right? PS I switched from Java.

Answer

Note, by the way, that in Java pointers are not used explicitly, i.e. the programmer can not in the code access the object through a pointer to it. However, in fact in Java all types except the base types are reference ones: they are accessed by reference, although it is impossible to explicitly pass the parameter by reference. And more, to the note, newin C ++ and in Java or C # – absolutely different things.

In order to give a little idea of ​​what pointers are in C ++, we give two similar code snippets:

Java:

Object object1 = new Object (); // New object
Object object2 = new Object (); // Another new object
object1 = object2; // Both variables refer to the object previously referenced by object2
// When you change the object referenced by object1, it will change and
// object2, because this is the same object

The closest equivalent to C ++:

Object * object1 = new Object (); // The memory is allocated for a new object
// This object is referenced by object1
Object * object2 = new Object (); // Similarly with the second object
delete object1;
// In C ++ there is no garbage collection system, so if this is not done,
// this program can no longer access this memory,
// at least, before the program is restarted
// This is called a memory leak
object1 = object2; // As in Java, object1 specifies the same where object2

However, this is a completely different thing (C ++):

Object object1; // New object
Object object2; // Another one
object1 = object2; // Full copying of object2 to object1,
// and not an override of the pointer is a very expensive operation
But will we get a gain in speed by referring directly to memory?

In fact, not at all. The work with pointers is in the form of a heap, while working with objects is a stack, a simpler and faster structure. If you are a beginner, then we have material for you, in which we tell in detail  what the stack and heap are .

Strictly speaking, this question unites two different issues. First: when should you use dynamic memory allocation? Second: when should you use pointers? Naturally, here we can not do without general words that it is always necessary to choose the most suitable tool for work. Almost always, there is an implementation better than using a dynamic allocation and / or raw pointers.

Dynamic distribution

In the formulation of the question, there are two ways to create an object. And the main difference lies in the time of their life (storage duration) in the program memory. By using Object myObject;, you rely on automatic lifetime determination, and the object will be destroyed immediately after exiting its scope. But it Object *myObject = new Object;saves the life of the object until the moment you manually remove it from the memory by the command delete. Use the latter option only when it is really necessary. So,  always make a choice in favor of automatically determining the shelf life of the object, if possible .

Usually, a forced life-span setting is applied in the following situations:

  • You need the object to exist after leaving the field of its visibility  – this is the object, exactly in this area of ​​memory, and not its copy. If for you it is not important (in most cases this is so), rely on automatic lifetime determination. However, here is an example of a situation where you might need to draw to an object outside its scope, but you can do this without storing it explicitly: by writing an object into a vector, you can “break off” the object itself – in fact it not its copy) will be available when called from the vector.
  • You need to use a lot of memory that can overflow the stack. It’s great if you do not have to deal with such a problem (and it’s very rare for it), because it’s “out of the box” of C ++, but unfortunately, sometimes you have to solve this problem.
  • You, for example, do not know exactly the size of the array that you have to use . As you know, in C ++ arrays have a fixed size in the definition. This can cause problems, for example, when reading user input. The pointer also defines only that part of the memory where the beginning of the array will be written, roughly speaking, without limiting its size.

If the use of dynamic allocation is necessary, then you should encapsulate it using a smart pointer ( what is a smart pointer you can read in our article) or another type that supports the idiom “Getting a resource is initialization” (the standard containers it supports is an idiom, according to which resource: a block of memory, a file, a network connection, etc. – upon receiving it is initialized in the constructor, and then it is destroyed neatly by the destructor). Intelligent are, for example, pointers std::unique_ptrand std::shared_ptr.

Pointers

However, there are cases when the use of pointers is justified not only from the point of view of dynamic memory allocation, but almost always there is an alternative way, without using pointers, which you should choose. As before, let’s say: always make a choice in favor of an alternative, if there is not a particular need for using pointers .

In cases where the use of pointers can be considered as an option, the following can be named:

  • Reference semantics . Sometimes it may be necessary to refer to an object (regardless of how the memory is allocated to it), since you want to refer to functions in that object, rather than its copy – ie. when you need to implement the transfer by reference. However, in most cases, it is sufficient to use the link, not the pointer, because it is for this purpose that the links are created. Note that these are somewhat different things with what is described in paragraph 1 above. But if you can refer to a copy of the object, then you do not need to use the link (but notice that copying an object is an expensive operation).
  • Polymorphism . Calling functions within a polymorphism (dynamic object class) is possible with a link or pointer. Again, the use of links is more preferable.
  • Optional object . In this case, you can use nullptrto indicate that the object is omitted. If this is a function argument, then it’s best to implement the implementation with default arguments or overload. On the other hand, you can use a type that encapsulates this behavior, for example  boost::optional(modified in C ++ 14 std::optional).
  • Increase the speed of compilation . You may need to separate the  compilation units . One of the effective applications of pointers is a preliminary declaration (for you need to determine it beforehand to use the object). This will allow you to distribute the compilation units, which can positively affect the acceleration of compilation time, dramatically decreasing the time spent on this process.
  • Interaction with the library C or C-like . Here you have to use raw pointers, freeing the memory from under which you produce at the last minute. You can get a raw pointer from a smart pointer, for example, by an operation get. If the library uses memory, which must then be released manually, you can issue the destructor in a smart pointer.
Comments