Reputation: 3905
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
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
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
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