C++ 为什么类的向量比有向量的类快
他尝试了下面的例子,但不明白为什么会这样 先例C++ 为什么类的向量比有向量的类快,c++,performance,c++17,C++,Performance,C++17,他尝试了下面的例子,但不明白为什么会这样 先例 #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&
#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;
}
我试着用不同的方式来模拟蚂蚁农场。第一种方法是将Ant作为一个类,并将Antfarm存储在Ant的向量中。第二种方法是使用一个AntFarm类,该类中有int的向量
现在,当我调用GetWorker时,我认为第一种方法会比第二种方法慢。但事实证明,第一种方法是为什么更快
有人能解释为什么方法1比方法2快吗
编辑:
我使用MSCV编译器版本16.9.0+5e4b48a27和以下编译选项为Windows 10 x64编译:/GT/GS/GS/guard:cf$我替换了我自己的计时器类,因为您没有提供计时器类,所以它以纳秒而不是毫秒打印 在发布版本中运行代码会产生
Farm time passed = 660100
Ant time passed = 0
因此,在第二种情况下,它显然优化了您的循环,因为在第一种情况下,它没有明显的副作用,但仍然可以做一些工作
将AntFarm::GetWorker更改为使用数组索引而不是.at()
让我们得到预期的结果
Farm time passed = 0
Ant time passed = 0
现在我们可以添加一些可见的副作用,以便代码实际运行。我只是在循环外移动了一个,然后打印出来,这样就不能优化了
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";
显然,在向量上使用.at()的成本更高,因为它会进行边界检查,但使用数组语法更快。您需要指定编译方式(操作系统、编译器、编译器版本、使用的开关),以及true的其余部分(您的计时器类是什么?)。很可能是使用
.at()
(进行边界检查)而不是[]
(不进行边界检查)负责,但无论如何,这些循环都是无用的,所以一个好的优化编译器应该将它们编译成绝对无效的循环。你在测量“玩具”代码所花费的时间,而这些代码实际上没有做任何有用的工作。这会产生误导性的结果,而且往往是毫无意义的。好吧,当我在linux下运行“玩具”代码时,我得到的时间都是0。当我根据r_ahlskog的回答改变构建类型时,我可以观察到同样的谨慎。但在windows上,无论我在调试或发布中构建了什么,它总是打印相同的时间。这仍然可以优化为timer_farm.Start();timer_farm.Stop();很对,我有点惊讶它没有。我在午餐时把它打了出来,所以我觉得它很接近事实。
Farm time passed = 0
Ant time passed = 0
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";
m_worker[index]
Farm time passed = 109700
Ant time passed = 318600
m_worker.at(index)
Farm time passed = 550200
Ant time passed = 318200