D'une manière ou d'une autre, une réponse sans réponse qui est complètement fausse est restée acceptée et la plupart des votes positifs pendant ~7 ans. Ce n'est pas une question de pommes et d'oranges. Il ne s'agit pas d'une question à laquelle il faut répondre par de vagues clichés.
Pour une règle simple à suivre :
L'option 1 est plus rapide...
...mais cela ne devrait pas être votre plus grande préoccupation.
Tout d'abord, la différence est assez mineure. Deuxièmement, lorsque nous augmentons l'optimisation du compilateur, la différence devient encore plus petite. Par exemple, sur mon gcc-5.4.0, la différence est sans doute triviale lorsque l'optimisation du compilateur est de niveau 3 ( -O3
) :
Donc, en général, je recommande d'utiliser la méthode n° 1 chaque fois que vous rencontrez cette situation. Cependant, si vous ne pouvez pas vous rappeler laquelle est optimale, cela ne vaut probablement pas la peine de chercher à la découvrir. Choisissez simplement l'une ou l'autre et passez à autre chose, car il est peu probable que cela entraîne un ralentissement notable de votre programme dans son ensemble.
Ces tests ont été effectués en échantillonnant des tailles de vecteurs aléatoires à partir d'une distribution normale, puis en chronométrant l'initialisation des vecteurs de ces tailles à l'aide des deux méthodes. Nous conservons une variable somme fictive pour nous assurer que l'initialisation du vecteur n'est pas optimisée, et nous rendons aléatoires les tailles et les valeurs des vecteurs pour tenter d'éviter toute erreur due à la prédiction des branches, à la mise en cache et à d'autres astuces de ce type.
main.cpp
:
/*
* Test constructing and filling a vector in two ways: construction with size
* then assignment versus construction of empty vector followed by push_back
* We collect dummy sums to prevent the compiler from optimizing out computation
*/
#include <iostream>
#include <vector>
#include "rng.hpp"
#include "timer.hpp"
const size_t kMinSize = 1000;
const size_t kMaxSize = 100000;
const double kSizeIncrementFactor = 1.2;
const int kNumVecs = 10000;
int main() {
for (size_t mean_size = kMinSize; mean_size <= kMaxSize;
mean_size = static_cast<size_t>(mean_size * kSizeIncrementFactor)) {
// Generate sizes from normal distribution
std::vector<size_t> sizes_vec;
NormalIntRng<size_t> sizes_rng(mean_size, mean_size / 10.0);
for (int i = 0; i < kNumVecs; ++i) {
sizes_vec.push_back(sizes_rng.GenerateValue());
}
Timer timer;
UniformIntRng<int> values_rng(0, 5);
// Method 1: construct with size, then assign
timer.Reset();
int method_1_sum = 0;
for (size_t num_els : sizes_vec) {
std::vector<int> vec(num_els);
for (size_t i = 0; i < num_els; ++i) {
vec[i] = values_rng.GenerateValue();
}
// Compute sum - this part identical for two methods
for (size_t i = 0; i < num_els; ++i) {
method_1_sum += vec[i];
}
}
double method_1_seconds = timer.GetSeconds();
// Method 2: reserve then push_back
timer.Reset();
int method_2_sum = 0;
for (size_t num_els : sizes_vec) {
std::vector<int> vec;
vec.reserve(num_els);
for (size_t i = 0; i < num_els; ++i) {
vec.push_back(values_rng.GenerateValue());
}
// Compute sum - this part identical for two methods
for (size_t i = 0; i < num_els; ++i) {
method_2_sum += vec[i];
}
}
double method_2_seconds = timer.GetSeconds();
// Report results as mean_size, method_1_seconds, method_2_seconds
std::cout << mean_size << ", " << method_1_seconds << ", " << method_2_seconds;
// Do something with the dummy sums that cannot be optimized out
std::cout << ((method_1_sum > method_2_sum) ? "" : " ") << std::endl;
}
return 0;
}
Les fichiers d'en-tête que j'ai utilisés sont situés ici :