web-dev-qa-db-fra.com

Comment initialiser std :: vector à partir d'un tableau de style C?

Quel est le moyen le moins coûteux d’initialiser un std::vector À partir d’un tableau de style C?

Exemple: Dans la classe suivante, j'ai un vector, mais en raison de restrictions extérieures, les données seront transmises sous forme de tableau de style C:

class Foo {
  std::vector<double> w_;
public:
  void set_data(double* w, int len){
   // how to cheaply initialize the std::vector?
}

Évidemment, je peux appeler w_.resize() puis passer en boucle sur les éléments ou appeler std::copy(). Existe-t-il de meilleures méthodes?

148
Frank

N'oubliez pas que vous pouvez traiter les pointeurs comme des itérateurs:

w_.assign(w, w + len);
209
Pavel Minaev

Vous utilisez l'initialisation de Word, il est donc difficile de savoir s'il s'agit d'une affectation unique ou si elle peut se produire plusieurs fois.

Si vous avez juste besoin d'une initialisation ponctuelle, vous pouvez la placer dans le constructeur et utiliser le constructeur à deux vecteurs itérateur:

Foo::Foo(double* w, int len) : w_(w, w + len) { }

Sinon, utilisez assign comme précédemment suggéré:

void set_data(double* w, int len)
{
    w_.assign(w, w + len);
}
37
Mark B

Bien, Pavel était proche, mais il existe même une solution plus simple et élégante pour initialiser un conteneur séquentiel à partir d'un tableau de style c.

Dans ton cas:

w_ (array, std::end(array))
  • array nous donnera un pointeur vers le début du tableau (n'a pas attrapé son nom),
  • std :: end (array) nous apportera un itérateur à la fin du tableau.
11
Mugurel

Vous pouvez "apprendre" la taille du tableau automatiquement:

template<typename T, size_t N>
void set_data(const T (&w)[N]){
    w_.assign(w, w+N);
}

Espérons que vous pourrez changer l’interface en set_data comme ci-dessus. Il accepte toujours un tableau de style C comme premier argument. Il arrive juste de le prendre par référence.


Comment ça marche

[Mise à jour: voir ici pour une discussion plus complète sur l'apprentissage de la taille]

Voici une solution plus générale:

template<typename T, size_t N>
void copy_from_array(vector<T> &target_vector, const T (&source_array)[N]) {
    target_vector.assign(source_array, source_array+N);
}

Cela fonctionne car le tableau est transmis en tant que référence à un tableau. En C/C++, vous ne pouvez pas passer un tableau en tant que fonction. Au lieu de cela, il se décomposera en un pointeur et vous perdrez la taille. Mais en C++, vous pouvez passez une référence au tableau.

Passer un tableau par référence nécessite que les types correspondent exactement. La taille d'un tableau fait partie de son type. Cela signifie que nous pouvons utiliser le paramètre de modèle N pour connaître la taille pour nous.

Il pourrait être encore plus simple d’avoir cette fonction qui renvoie un vecteur. Avec les optimisations de compilateur appropriées en vigueur, cela devrait être plus rapide qu'il n'y parait.

template<typename T, size_t N>
vector<T> convert_array_to_vector(const T (&source_array)[N]) {
    return vector<T>(source_array, source_array+N);
}
9
Aaron McDaid

std::vector<double>::assign est la voie à suivre, car il s'agit de petit code. Mais comment ça marche, en fait? N'est-ce pas redimensionner et ensuite copier? Dans MS, la mise en œuvre de STL est exactement la même chose.

J'ai bien peur qu'il n'y ait pas de moyen plus rapide d'implémenter (ré) initialiser votre std::vector.

0
Janusz Lenar