【问题标题】:Performance comparison between three ways to read and store an array of objects三种方式读取和存储对象数组的性能比较
【发布时间】:2020-04-18 12:39:10
【问题描述】:

我正在尝试提高我在使用 C++ 解决问题方面的编码技能。因此,我很想知道以下三个建议示例中哪一个使用起来更快更好,以及评估性能的最佳方法。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5;

struct Car {
    int id, price;
    Car(int _id, int _price) : id(_id), price(_price) {}
};

struct Boat {
    int id, price;
};

struct Motorcycle {
    int id, price;
};

int main() {
    // ------------ section1 ------------
    int n1;
    scanf("%d", &n1);
    vector<Car> cars;
    for (int i = 0; i < n1; i++) {
        int id, price;
        scanf("%d%d", &id, &price);
        cars.emplace_back(id, price);
    }
    // ------------ section2 ------------
    int n2;
    scanf("%d", &n2);
    Boat boats[N];
    for (int i = 0; i < n2; i++) {
        int id, price;
        scanf("%d%d", &id, &price);
        boats[i] = {id, price};
    }
    // ------------ section3 ------------
    int n3;
    scanf("%d", &n3);
    vector<Motorcycle> motorcycles(n3);
    for (auto& motorcycle : motorcycles) {
        scanf("%d%d", &motorcycle.id, &motorcycle.price);
    }
    return 0;
}

不过,我相信普通数组比std::vector快。

【问题讨论】:

  • 与 std::vector 相比,非动态普通对象数组总是至少保存一个动态分配。这可能很重要,也可能不重要:如果对象本身需要任何初始化(这会导致 O(n) 的时间复杂度),那么足够大的数字总是会超过保证 O(log n) 的向量分配。此外,如果对象执行重要的默认初始化,或者赋值代价高昂,则将 emplace_back() 放入向量中会比覆盖数组中预先存在的对象执行得更好。
  • @Peter-ReinstateMonica 因此,如果可能的话,我应该始终使用普通数组。否则,如果我必须使用std::vector,那么在这种情况下我应该使用emplace_back() 而不是push_back(),对吧?谢谢。
  • 另外,第三种情况下的for auto&amp;呢?
  • 如果自动引用(是通过引擎盖下的交互器工作吗?)有什么不同,我会感到惊讶。至于使用什么:最简单、最惯用且最不容易出错的那个(通常是带有 auto 的向量)。性能差异很可能可以忽略不计。

标签: c++ performance c++11 auto emplace


【解决方案1】:

我所知道的访问矢量内容的最快和最安全的方法是首先分配存储空间(永远不要使用 push_back)。 并且取决于您的编译器:重用底层分配的指针来访问数据:这种用法类似于第 2 节,但可以使用动态分配的容器

struct Boat {
    int id, price;
};



int main(int)
{
    int n = 10; // whatever dynamic variable
    std::vector<Boat> boats;
    boats.resize(n);
    auto boats_ptr = boats.data();

    for (auto i=0;i<boats.size();i++)   
    {
        *boats_ptr = { i,2*i}; // or any other construction
        boats_ptr++;
    }
}

【讨论】:

  • 这意味着第三种方式总是优于第一种,如果我们将第三种方式中的向量替换为普通数组(大小相同),那么我们将获得最佳性能其中,对吧?
  • 你可以保留一个vector,它总是比普通数组好,因为它支持动态内存分配,而且很安全(不需要删除它)。重要的是分配向量(在构建时或调整大小(非保留))。并使用其底层 data() 指针遍历它。 ptr++ 所需的机器指令比 iterator++ 少。请注意,data() 生命周期与实际向量大小相关。
  • 你看到彼得的评论了吗? “与 std::vector 相比,非动态普通对象数组始终至少保存一个动态分配”。
  • @catfour。当然可以,但是分配的性能成本(完成一次)与访问数据的性能成本(通常对所有元素都完成)相比可以忽略不计。
猜你喜欢
  • 2017-02-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-26
相关资源
最近更新 更多