user2436815
user2436815

Reputation: 3905

C++ Vector: push_back Objects vs push_back Pointers performance

I'm testing performance difference between pushing back Objects vs pushing back object Pointers to Vector in C++.

I've read in Stackoverflow and other articles that you should avoid pushing back pointers unless you must do so...

However, I realized that there is a HUGE performance gain for pushing back Pointers,,,

This is a simple test I ran:

tstart = chrono::system_clock::now();

vector<MyObject> VectorOfObjects;
for (int i=0; i<10000; i++) {
    MyObject x("test");
    VectorOfObjects.push_back(x);
}

tend = chrono::system_clock::now();
tt = tend-tstart;
cout << "Pushback Object: " << tt.count()*1000 << " Milliseconds\n" << endl;




tstart = chrono::system_clock::now();

vector<MyObject *> VectorOfPointers;
for (int i=0; i<10000; i++) {
    VectorOfPointers.push_back(new MyObject("test"));
}

tend = chrono::system_clock::now();
tt = tend-tstart;
cout << "Pushback Pointers: " << tt.count()*1000 << " Milliseconds\n" << endl;


The result is actually pretty surprising:

Pushback Objects:  989 Milliseconds
Pushback Pointers: 280 Milliseconds


As you can see, pushing back pointers is 3~4 times faster than pushing back objects! which is a huge performance difference, especially when dealing with large volume of data.

So my question is: WHY NOT USE Vector of Pointers??

Answers to almost every post on Stackoverflow regarding similar question says Avoid Vector of Pointers..

I know memory leakage might be a problem,, but we can always use Smart Pointers,, and even manually deleting the pointers at destruction is not that difficult..

I'm also curious about the cause of this performance difference..

Thanks


UPDATE:

Actually I tested on ideone .... and here, pushback objects is Faster!!!

In Visual Studio,, pushing back Objects was Wayyy slower..

Why is this...??

Upvotes: 2

Views: 10057

Answers (3)

Nikos Athanasiou
Nikos Athanasiou

Reputation: 31549

To be fair, when measuring your code you should account for deallocation of all those pointers. A sample code would read as :

#include <chrono>
#include <string>
#include <iostream>
#include <functional>
#include <vector>

using namespace std;

// 1. A way to easily measure elapsed time -------------------
template<typename TimeT = std::chrono::milliseconds>
struct measure
{
    template<typename F>
    static typename TimeT::rep execution(F const &func)
    {
        auto start = std::chrono::system_clock::now();
        func();
        auto duration = std::chrono::duration_cast< TimeT>(
            std::chrono::system_clock::now() - start);
        return duration.count();
    }
};
// -----------------------------------------------------------


// 2. MyObject -----------------------------------------------
struct MyObject {
    string mem;
    MyObject(const char *text) : mem(text) {};
};
// -----------------------------------------------------------


int main() 
{
    vector<MyObject> VectorOfObjects;
    vector<MyObject *> VectorOfPointers;

    cout << "Pushback Object: " << measure<>::execution([&]()
    {
        for (int i = 0; i < 100000; i++) {
            MyObject x("test");
            VectorOfObjects.push_back(x);
        }
    }) << endl;


    cout << "Pushback Pointers: " << measure<>::execution([&]()
    {
        for (int i = 0; i < 100000; i++) 
            VectorOfPointers.push_back(new MyObject("test"));
        for (auto &item : VectorOfPointers) 
            delete item;
    }) << endl;

    return 0;
}

and when compiled with

g++ -std=c++11 -O3 -march=native -Wall -pedantic

the results are (I'm using +1 order of magnitude in the for loops) :

Pushback Object: 20

Pushback Pointers: 32


  • If you used

    VectorOfObjects.emplace_back("test");

    The duration of the VectorOfObjects modification would drop to 18

  • If you preallocated both vectors

    vector<MyObject> VectorOfObjects;
    VectorOfObjects.reserve(100000);
    
    vector<MyObject *> VectorOfPointers;
    VectorOfPointers.reserve(100000);
    

    the result would be 17-34 (for the vector of objects again)

  • If you use a vector of unique pointers then the results are similar

    vector<unique_ptr<MyObject>> VectorOfPointers;
    

    note that I'm limiting the scope of the vectors to explicitly account for the destruction of the smart pointers

  • Other choices would include boost's pointer containers in which case the related data structure would be a pointer vector

Upvotes: 4

Yasser Asmi
Yasser Asmi

Reputation: 1180

The way your sample code is written, there is definitly a memory leak problem. Agreed that you can fix that problem by doing a deletes.

It can be done but it is just cumbersome. If you take care of things like memory leaks, it is fine.

The root issue for performance here is that there are copies of objects being made. You create an object. When you add it to the vector. It creates a new object and copies yours using the copy constructor.

C++11 improves the situation a bit by introducing emplace_back(). So if you are using C++11, you may be able to get the same performance by using emplace.

Upvotes: 2

Darrell
Darrell

Reputation: 648

I prefer to use shared pointers opposed to regular pointers and I always use them when I can.

I use shared pointers with vectors when dealing with the vector changing a lot.

You should avoid regular pointers when dealing with vectors, as they need to be manually destructed and will just cause memory leaks.

So to answer your question...

Look into the shared_ptr library and use those instead here is a link http://www.cplusplus.com/reference/memory/shared_ptr/

hope this answers your question

Upvotes: 2

Related Questions