Why is this so much slower in C++?

后端 未结 9 2007
盖世英雄少女心
盖世英雄少女心 2020-12-31 11:49

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

相关标签:
9条回答
  • 2020-12-31 12:29

    The whileloop 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!

    0 讨论(0)
  • 2020-12-31 12:29

    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.

    0 讨论(0)
  • 2020-12-31 12:29

    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.

    0 讨论(0)
  • 2020-12-31 12:34

    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.

    0 讨论(0)
  • 2020-12-31 12:40

    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++.

    0 讨论(0)
  • 2020-12-31 12:40

    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.

    0 讨论(0)
提交回复
热议问题