2

I heard pointers are not recommended in C++ but I don’t understand why.

My problem is I want to create a vector of class objects to manage my classes.

vector<MyClass> vectorOfClass;

Naturally, for better performance, I should go with a vector of a pointer of class objects?

vector<MyClass *> vectorOfClass;

Or maybe is it possible to create a vector of reference of class objects?

vector<MyClass &> vectorOfClass;

So my questions are :

  • What is the difference between these ways?
  • What is the most optimized to create a vector of class objects?
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
Guillaume
  • 191
  • 10
  • 6
    `I heard pointers are not recommended in C++` where exactly? – Empty Space Nov 08 '19 at 17:47
  • 2
    @MutableSideEffect generally pointer are best avoided if they are unecessary for the current use case. Many java or C# developper will come to C++ and start using pointer absolutely everywhere just to be able use `new` on types. – Guillaume Racicot Nov 08 '19 at 17:49
  • You cannot create vectors or arrays of references, you'd need to use `std::reference_wrapper`. – Jesper Juhl Nov 08 '19 at 17:49
  • 4
    `std::vector` should be a default choice. – Evg Nov 08 '19 at 17:51
  • 1
    "Naturally, for better performance, I should go with a vector of a pointer of class objects?" Naturally? pointers have their place but C++, unlike C, provides for things like `vector` which rarely benefit. Internally, they use pointers to locate objects stored on the heap and do what you have to do manually with pointers in C. – doug Nov 08 '19 at 17:51
  • What is not recommended is using "raw pointers" but instead use "smart pointers". Pointers are constructive as much destructive. – Itachi Uchiwa Nov 08 '19 at 17:59
  • 1
    *Naturally, for better performance, I should go with a vector of a pointer of class objects?* -- A `std::vector` guarantees that all of those `MyClass` instances are in contiguous memory (i.e. more likelihood to be in the cache). This is not so with a `std::vector`. – PaulMcKenzie Nov 08 '19 at 18:00
  • In addition, excessive usage of pointers in an attempt to beat the compiler at the speed game rarely, if ever works out. Maybe back a generation ago in the `C` world, doing tricky things with pointers caused a speed up, but in this day and age, using too many pointers may render the code unoptimizable by the compiler. Thus pointer-ed up code could run slower, not faster. – PaulMcKenzie Nov 08 '19 at 18:11
  • Depends heavily on the intended [access pattern](https://en.wikipedia.org/wiki/Memory_access_pattern) – user4581301 Nov 08 '19 at 18:27

5 Answers5

8

Or maybe is it possible to create a vector of reference of class objects?

No. Reference are not objects in C++. So you can't create arrays of reference or pointer to references. You can however use a std::reference_wrapper, which wraps reference in an object.

What is the most optimized to create a vector of class objects?

Depends always on the situation. Mesure, profile and make your decision according to your data.

What is the difference between these ways?

They are stored in different ways.

A vector of values look like this in memory:

+----------------------+
| std::vector<MyClass> |----
+----------------------+   |
                           |
   -------------------------
   |
   v
+-------------+-------------+-------------+-------------+
|   MyClass   |   MyClass   |   MyClass   |   MyClass   |
+-------------+-------------+-------------+-------------+

Whereas a vector of pointer look like this:

+-----------------------+
| std::vector<MyClass*> |---
+-----------------------+  |
                           |
          ------------------
          |
          v
       +-------+-------+-------+-------+
       |  ptr  |  ptr  |  ptr  |  ptr  |
       +-------+-------+-------+-------+
           |       |      |          |
           v       |      v          |
+-------------+    | +-------------+ |
|   MyClass   |    | |   MyClass   | |
+-------------+    | +-------------+ |
                   v                 v
        +-------------+         +-------------+
        |   MyClass   |         |   MyClass   |
        +-------------+         +-------------+

Both have advantages and disadvantages.

For the value:

  • Pro: Contiguous in memory. There is no pointer chasing and usually really fast to iterate.
  • Pro: Automatic memory managemen. Vector will manage the memory of every values it allocates.
  • Con: Reference invalidation. Resizing the vector will invalidate every reference to the objects inside it.
  • Con: In slower to resize with non-trivial objects. Resizing involve moving objects around. That may be slower with large or non-trivial objects.

For pointer:

  • Pro: No reference invalidation. The address of the object are managed by you.
  • Pro: Faster reallocation, since it will be the cost of copying pointers around instead of moving objects around.
  • Con: Slow iteration. For each element in the vector, the CPU will have to ask the memory for it and cannot use its cache efficiently.
  • Con: You must use std::unique_ptr to own the memory, and most likely allocate every objects distinctly. Allocating a large amount of distinct objects is slow.

The default choice should be std::vector<MyClass>. This is by far the simplest and work for most cases. Usually when I need references to those objects, I tend to use index in the vector which are stable as long as there are no element removed in the middle.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
3

I heard pointers are not recommended in C++

You may have misunderstood. While there are cases where there are superior alternatives to pointers, as well as cases where pointers can - but shouldn't - be used unnecessarily, there is no general recommendation against pointers regardless of use case.

Naturally, for better performance, I should go with a vector of a pointer of class objects?

Pointers are not magic that improve performance just by existing. In fact, there is a good possibility that they worsen the performance. Indirecting through a pointer is not free.

Or maybe is it possible to create a vector of reference of class objects?

It is not possible. The element type of vector, or any other container cannot be reference. std::reference_wrapper can be used instead.

What is the difference between these ways?

vector<MyClass> stores MyClass objects in the vector. vector<MyClass*> stores pointers in the vector. vector<MyClass&> violates the requirements of vector and is ill-formed.

What is the most optimized to create a vector of class objects?

The most efficient thing to do is nothing. Not creating a vector at all will be at least as fast, and potentially faster than creating a vector. Before understanding how to create a vector optimally, you must first understand what you're trying to achieve by creating the vector.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

Consider the ownership and let that guide your decision:


If the vector owns them then it is best to use

vector<MyClass> vectorOfObjects;

or

vector<std::unique_ptr<MyClass>> vectorOfObjects;

This last one is useful if you must have a pointer (to a polymorphic base), but you still want the vector to own the object.


If the ownership lies elsewhere, but you wish to change each pointer from time to time, then use

vector<MyClass*> vectorOfObjects;

But in this case you might want to look into rather using smart pointers:

vector<shared_ptr<MyClass>> vectorOfObjects;

Finally, you cannot use vector<MyClass &> vectorOfObjects; but you can use std::reference_wrapper:

vector<std::reference_wrapper<MyClass>> vectorOfObjects;

Again this might only be useful if the vector doesn't own the objects.


As for performance, each time memory is allocated there might be a cost, so using pointers after the objects were created can help, but it is best to start simple and then measure. vector<MyClass> vectorOfObjects; might even perform better. You won't know until you measure. This has been explored in this answer.

wally
  • 10,717
  • 5
  • 39
  • 72
0

Naturally, for better performance,

This is not that simple to assume. Having a vector of pointers mean the actual values can only be reached via 2 pointer redirection - one for the indexing and the next for the actual value access. These pointers could be anywhere in the memory. So accessing them could result in plenty of cache misses. It is a good idea to keep the objects as such in the vector. Change that pattern only if one has sufficient evidence (= profile results).

Axeon Thra
  • 334
  • 3
  • 14
0

I heard pointers are not recommended in C++ but I don’t understand why.

Pointers are a lot harder to work with than say, regular objects. It's not that they are completely bad, it's just that there are just so many better options in almost every use case for pointers.

So for instance, say you have a function parameter you'd like to modify in the caller function. In C, you'd use a pointer:

void func(int* someMumber) {
    *somenumber = 3; // modifies value in caller
}

In C++, this is replaced with passing by reference:

void func(int& someMumber) {
    somenumber = 3; // modifies value in caller
}

This way, there is no messy syntax to deal with, and no fear of getting passed a bad pointer, etc. This should always work no matter what the caller passes us.^1

Another example is let's say you want dynamically allocated data:

int* dynamicArray = new int[size];

When you're done with it, you will have to remember to delete it:

delete [] dynamicArray;

This can get messy, and then you have to keep track of what you did and didn't delete. And then if you don't delete something, that creates a memory leak.

C++ has a much better solution for this: std::vector. Then I can add as many elements to the array the instant I need them:

std::vector<int> dynamicArray;

// later, when I need to store a value
dynamicArray.push_back(someValue);

No worrying about leaked data, or anything like that. It will all just deallocate automatically when it's done.

Need a pointer anyway for other some reason? Try a smart pointer:

std::unique_ptr<int> ptr = new int;

Smart pointers deallocate data automatically without you have to worry about it. It just makes your life easier. Plus, you can convert these to "raw" pointers whenever you need to.

So it's not that they are bad, it's just they are made obsolete by other things. Thus, they are not recommended.

Naturally, for better performance, I should go with a vector of a pointer of class objects?

The compiler will optimize a lot for you, so there isn't a lot of need to worry about this. On the other hand, using pointers will make things a lot harder on yourself. You might want to consider one of the above options instead.

Or maybe is it possible to create a vector of reference of class objects?

Not sure if this is directly possible, but it might be possible with a std::reference_wrapper.

So my questions are :

What is the difference between these ways?

What is the most optimized to create a vector of class objects?

The biggest difference is that if you push the address of a local variable to your pointer vector, and it goes out of scope, you vector will be filled with garbage. To do this properly, you will need to allocate a new object. Then you will have to delete it. It's just a lot more work.

If you use a vector of references, you will run into the same types of scope problems that using a local variable address will create.

If you store it by value, you won't have to worry about any of this.

Again, don't worry about optimizations. The compiler will figure that out for you. If you are trying to do this as an optimization, you are just making more work for yourself.


1: Actually, the caller can't pass literals to us, because non-const references can't bind to literals. But that is beside the point here.

  • 1
    Sidenote: prefer `std::unique_ptr ptr = std::make_unique();` to `std::unique_ptr ptr = new int;` if compiling to C++14 or better. It closes a few possible holes such as a failure constructing the `unique_pr` leaving the `new`ed `int` still alive and leaked. – user4581301 Nov 08 '19 at 18:25
  • Good point. I'm still used to C++ 11. I'll edit when I get a chance, or feel free to edit and add it in. –  Nov 08 '19 at 19:24