I have converted this simple method from C# to C++. It reads a path table and populates a list of lists of ints (or a vector of vectors of ints).
A sample line from
The while
loop in your code seems to be very messy and long, as it is doing things in a way which is not needed:
A simple and fast equivalent code would be this:
int result;
stringstream ss(line);
while ( ss >> result ) //reads all ints untill it encounters non-int
{
pathLookupVectors[i][j].push_back(result);
}
In C++, such loop is idiomatic as well. Or instead of this manual loop, you could write use std::copy
1:
std::copy(std::istream_iterator<int>( ss ),
std::istream_iterator<int>(),
std::back_inserter(pathLookupVectors[i][j]));
1. It is taken from @David's comment.
Or even better if you do this, when you push_back
the vector itself:
if (getline(myFile, line)) //enter if a line is read successfully
{
stringstream ss(line);
std::istream_iterator<int> begin(ss), end;
pathLookupVectors[i].push_back(vector<int>(begin, end));
}
Done!
Both List.Add
and vector::push_back
reallocate memory from time to time as the container grows. C++ vector stores subvectors by value, so all their data (which seem to be huge in your case) is copied again and again. In contrast, C# list stores sublists by reference, so sublists' data is not copied during reallocation.
Typical vector implementation doubles its capacity during reallocation. So if you have 1 million of lines, subvectors will be copied log(2,1000000) ≈ 10 times.
Move semantics introduced in C++11 is supposed to eliminate this effect. Until that, try vector< shared_ptr< vector<int> > >
, list< vector<int> >
, or, if you know future size in advance, use vector::reserve()
to avoid reallocations.
Haven't tested the code but how many ints
does it typically load? Consider what happens when each of your vectors
reaches its capacity
. A vector
grows inefficiently - O(n) I believe. C#'s List
doesn't have this behaviour.
Consider using std::deque
, std::list
or some other container that has better growth behaviour. See this article for more info.
I'm not exactly sure what is going on here, but I see a few ways in which you can optimize your code. If this doesn't get you there, then there might be something else going on.
How big are your strings? As you are passing them in your C++ version, you are making copies because you are "passing by value". Try passing it by constant reference:
void Level::PopulatePathVectors(const string &pathTable)
This passes the object by reference, meaning it is not making a copy. Then, it is customary to make it const
to ensure that it is not getting modified in your function.
Use .append
or +=
to extend tempString
. I believe you are making a new string object, then replacing the old one with just +
, while +=
and .append
are going to modify the current one in place:
tempString.append(line[count]);
You can also tweak out a bit more performance by declaring your variables at the top and then reassigning into them. This will prevent them from getting recreated every time. For example, put string line;
before your for-loop, because it's going to get overwritten anyways.
There are a few places you can do this, such as with tempString
.
If you have extremely large number of elements, you'll be punished with re-allocation and copy every time vector is pushed-back. Try using a different container in C++.
Since your function itself is not slow1, the reason for the program being slow must be that some code that uses the product of this function becomes slower when pathLookupVectors
has been populated.
I think running a profiler on your program would be the best way to find out, but you could also look through your code and find every piece of code that depends on pathLookupVectors
and consider if it could be the bottleneck you're searching for.
1. Established in your latest edit.