简体   繁体   中英

Why is a vector of classes faster then class with vector

Hi tried the following example and dont understand why it is how it is.

Example first

#include <iostream>
#include <vector>

class Ant {
private:
  int m_worker;

public:
  Ant(int x=0) : m_worker(x) {}

  int GetWorker() const {
      return m_worker;
  }
};

class AntFarm {
private:
  std::vector<int> m_worker;

public:
  AntFarm() : m_worker(100) {}

  int GetWorker(int index) const {
      return m_worker.at(index);
  }
};


int main() {
  AntFarm farm{};
  std::vector<Ant> vec(100);
  Timer timer_farm{};
  Timer timer_ant{};

  timer_farm.Start();
  for(int j=0;j<10000;j++) {
      for(int i=0;i<100;i++) {
          int a = farm.GetWorker(i);   
      }
  }
  timer_farm.Stop();

  timer_ant.Start();
  for(int j=0;j<10000;j++) {
      for(const auto ant : vec) {
          int a = ant.GetWorker();
      }
  }
  timer_ant.Stop();

  std::cout << "Farm time passed = "<<timer_farm.Milliseconds() << std::endl;
  std::cout << "Ant time passed = "<<timer_ant.Milliseconds() << std::endl;
  return 0;
}

Output:

Farm time passed = 30
Ant time passed = 2

I tried to model an Antfarm differently. First approach is to have an Ant as a class and store the Antfarm in an vector of Ant's. Second approach is to have an AntFarm class who has a vector of int's within.

Now when i call GetWorker i thought the first approach will be slower then the second. But turns out the first approach is why faster.

Can anyone explain why approach 1 is faster then approach 2?!

EDIT:

I compiled for Windows 10 x64 with MSCV compiler Version 16.9.0+5e4b48a27 and following compile options: /GT /GS /Gs /guard:cf $<$CONFIG:Debug:/RTC1>

I substituted my own timer class as you did not provide one so it prints in nanoseconds instead of milliseconds.

Running your code in release build produces

Farm time passed = 660100
Ant time passed = 0

So it obviously optimizes away your loop in the second case since it has no visible side effects in the first case it still does some work.

Changing your AntFarm::GetWorker to use array indexing instead of.at()

int GetWorker(int index) const {
    return m_worker[index];
}

gets us the expected result.

Farm time passed = 0
Ant time passed = 0

Now we can add in some visible side effects so that the code is actually run. I just moved a outside the loop and print it after we are done so it can't be optimized away.

timer_farm.Start();
int a;
for(int j=0;j<10000;j++) {
    for(int i=0;i<100;i++) {
        a = farm.GetWorker(i);
    }
}
timer_farm.Stop();
std::cout << a;

timer_ant.Start();
for(int j=0;j<10000;j++) {
    for(const auto ant : vec) {
        a = ant.GetWorker();
    }
}
timer_ant.Stop();
std::cout << a << "\n";

Now we get some results on both.at and []

m_worker[index]
Farm time passed = 109700
Ant time passed = 318600

m_worker.at(index)
Farm time passed = 550200
Ant time passed = 318200

So clearly using.at() on vector here costs more since it does bounds checking but using array syntax it is faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM