0

I'm trying to improve my coding skills in problem-solving using C++. Hence, I'm curious to know which one of the following three suggested examples is faster and better to use, as well as the best way to evaluate the performance.

#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;
}

However, I believe that the ordinary array is faster than the std::vector.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
catfour
  • 119
  • 3
  • 10
  • 1
    An non-dynamic ordinary array of objects *always* saves at least one dynamic allocation compared to a std::vector. That may or may not be significant: If the objects themselves need any initialization (which leads to a time complexity of O(n)) sufficiently large numbers will always outweigh the vector allocation which has a guaranteed O(log n). Also, if the objects perform significant default initialization, or if assignment is expensive, emplace_back() into a vector will perform better than overwriting pre-existing objects in an array. – Peter - Reinstate Monica Apr 18 '20 at 12:48
  • @Peter-ReinstateMonica So, I should always use an ordinary array if that is possible. Otherwise, if I have to use a `std::vector`, then I should use `emplace_back()` instead of `push_back()` in this case, right? Thank you. – catfour Apr 18 '20 at 16:26
  • Also, what about the `for auto&` in the third case? – catfour Apr 18 '20 at 16:30
  • I'd be amazed if the auto reference (is that working through an interator under the hood?) made any difference. As to what to use: The one which is easiest, most idiomatic and least error prone (usually a vector with auto). The performance differences are most likely negligible. – Peter - Reinstate Monica Apr 18 '20 at 17:06

1 Answers1

1

The quickest and safest I know for accessing vector content is allocating storage first (never use push_back). And depending of your compiler: reuse of the underlying allocated pointer for accessing the data: this usage is similar to section 2 but can use dynamically allocated container

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++;
    }
}
Jean-Marc Volle
  • 3,113
  • 1
  • 16
  • 20
  • This means that the third way is always better than the first one, and if we replace the vector in the third way with an ordinary array (with the same size), then we will get the best performance among them, right? – catfour Apr 20 '20 at 18:52
  • You can keep a vector, it is always better than ordinary array because it support dynamic memory allocation and it's safe (no need to delete it). What is important is allocating the vector (at construction time or with resize (not reserve)). And iterating through it using its underlying data() pointer. There are less machine instruction required for ptr++ than iterator++. Beware that the data() life span is linked to the actual vector size. – Jean-Marc Volle Apr 21 '20 at 05:56
  • Did you see Peter's comment? "An non-dynamic ordinary array of objects always saves at least one dynamic allocation compared to a std::vector". – catfour Apr 21 '20 at 06:26
  • 1
    @catfour. Sure but the performance cost of allocation (done once) is negligeable vs the performance cost of accessing the data (usually done for all elemets). – Jean-Marc Volle Apr 21 '20 at 07:38