Je suis de portage de certaines C99 code qui fait un usage intensif de la longueur variable des tableaux (VLA) à C++.
J'ai remplacé le VLAs (allocation de pile) avec un tableau de classe qui alloue de la mémoire sur le tas. La performance succès a été énorme, un ralentissement d'un facteur d'au moins 3,2 (voir les repères ci-dessous). Ce rapide VLA remplacement puis-je utiliser en C++? Mon objectif est de minimiser le gain de performance lors de la réécriture du code pour C++.
Une idée qui m'a été suggéré de préparer une classe array qui contient une taille fixe de stockage au sein de la classe (c'est à dire peut être pile-alloués) et l'utilise pour les petits tableaux, et passe automatiquement à l'allocation de tas pour les grandes baies. Mon implémentation est à la fin du post. Il fonctionne assez bien, mais je ne peut toujours pas atteindre la performance de l'original C99 code. Pour venir près d'elle, je dois augmenter cette taille fixe de stockage (MSL
ci-dessous) pour les tailles dont je ne suis pas à l'aise avec. Je ne veux pas allouer trop de tableaux de grande sur la pile de même pour les nombreux petits tableaux qui n'en ont pas besoin parce que j'ai peur qu'il va déclencher un débordement de pile. Un C99 VLA est en fait de moins en moins enclins à présent, car il ne sera jamais utiliser plus d'espace de stockage que nécessaire.
Je suis tombé sur std::dynarray
, mais ma compréhension est qu'il n'a pas été acceptée dans la norme (encore?).
Je sais que clang et gcc soutien VLAs en C++, mais j'en ai besoin pour travailler avec MSVC trop. En fait, une meilleure portabilité est l'un des principaux objectifs de la réécriture en C++ (l'autre objectif étant de rendre le programme, qui était à l'origine un outil de ligne de commande, dans une bibliothèque réutilisable).
Référence
MSL
se réfère à la taille du tableau ci-dessus qui j'ai passer de tas de répartition. J'ai utiliser des valeurs différentes pour les codes 1D et 2D tableaux.
Original C99 code: 115 secondes.
MSL = 0 (c'est à dire d'allocation de tas): 367 secondes (3,2 x).
1D-MSL = 50, 2D-MSL = 1000: 187 secondes (1.63 x).
1D-MSL = 200, 2D-MSL = 4000: 143 secondes (1,24 x).
1D-MSL = 1000, 2D-MSL = 20000: 131 (1.14 x).
L'augmentation de MSL
améliore encore les performances de plus, mais finalement, le programme va commencer à retourner des résultats faux (je suppose en raison d'un débordement de pile).
Ces points de référence sont avec clang 3.7 sur OS X, mais gcc 5 montre des résultats très similaires.
Code
C'est l'actuel "smallvector" mise en œuvre que j'utilise. J'ai besoin de 1D et 2D vecteurs. - Je passer en tas-de l'allocation au-dessus de la taille de l' MSL
.
template<typename T, size_t MSL=50>
class lad_vector {
const size_t len;
T sdata[MSL];
T *data;
public:
explicit lad_vector(size_t len_) : len(len_) {
if (len <= MSL)
data = &sdata[0];
else
data = new T[len];
}
~lad_vector() {
if (len > MSL)
delete [] data;
}
const T &operator [] (size_t i) const { return data[i]; }
T &operator [] (size_t i) { return data[i]; }
operator T * () { return data; }
};
template<typename T, size_t MSL=1000>
class lad_matrix {
const size_t rows, cols;
T sdata[MSL];
T *data;
public:
explicit lad_matrix(size_t rows_, size_t cols_) : rows(rows_), cols(cols_) {
if (rows*cols <= MSL)
data = &sdata[0];
else
data = new T[rows*cols];
}
~lad_matrix() {
if (rows*cols > MSL)
delete [] data;
}
T const * operator[] (size_t i) const { return &data[cols*i]; }
T * operator[] (size_t i) { return &data[cols*i]; }
};