1
votes

Bonne façon de boucler sur std :: array

Considérez le std :: tableau de pointeurs vers char suivant:

for(size_t i {0}; i < m_arr.size(); i++) {
        if(m_arr.at(i) != m_arr.back()) {
            std::cout << m_arr.at(i) << std::endl;
        }
    }

Je sais que je peux parcourir le tableau en utilisant le code suivant

    // test variables
    int x {100};
    double y {3.14};
    int* x_ptr {&x};
    double* y_ptr {&y};

    // std::array of pointer to char
    std::array<char*, 10> m_arr;

    // set the first two elements of m_arr
    char buf1[16];
    sprintf_s(buf1, "%p", x_ptr);
    m_arr.at(0) = buf1;
    char buf2[16];
    sprintf_s(buf2, "%p", y_ptr);
    m_arr.at(1) = buf2;

    for(size_t i {0}; i < m_arr.size(); i++) {
            std::cout << m_arr.at(i) << std::endl;
    }

Mais cette approche lève l'exception "Emplacement de lecture de violation d'accès", lorsque le i-ème élément n'est pas affecté correctement. Par exemple, le code suivant attribue les deux premiers éléments mais le troisième élément, m_arr.at (3) , déclenche l'erreur susmentionnée:

for(size_t i {0}; i < m_arr.size(); i++) {
            std::cout << m_arr.at(i) << std::endl;
    }

I a trouvé une solution rapide à ce problème en vérifiant le i-ème élément avec le dernier élément du tableau pour ignorer les éléments non attribués, mais ce n'est évidemment pas une réponse claire

std::array<char*, 10> m_arr;

Je crois qu'il y a est un meilleur moyen de parcourir ce tableau et d'éviter l'erreur. Merci d'avance pour votre aide.


6 commentaires

Je ne pense pas que votre «solution» corrige quoi que ce soit. Quoi qu'il en soit, le problème n'est pas de boucler sur l'élément. Il s'agit de dé-référencer des pointeurs non initialisés.


Lorsque vous savez que l'index sera valide, il n'y a rien de mal à utiliser operator [] au lieu de at . En principe, at a la charge de vérifier l'index à chaque fois qu'il est appelé.


La première question serait: pourquoi utilisez-vous char * au lieu de std :: string ?


@UnholySheep C'est probablement le cas où une fonction API sous-jacente ou similaire utilise char * , et l'OP suppose qu'ils doivent également utiliser char * dans leur programme pour communiquer avec le API. J'ai vu cette hypothèse erronée trop souvent pour ne pas la remarquer.


@UnholySheep C'est un peu compliqué mais std :: string n'est pas une option


@ FrançoisAndrieux Merci. Je ne savais pas ça.


3 Réponses :


2
votes

Initialisez votre tableau:

for (auto ptr : m_arr) {
    if (ptr) std::cout << ptr << std::endl;
}

alors vous pouvez vérifier la sécurité pour une valeur non-nullptr:

std::array<char*, 10> m_arr{}; // nullptr initialized


1 commentaires

@NathanOliver: corrigé.



1
votes

Le problème n'est pas tant la manière dont vous itérez le tableau, mais plutôt ce que le tableau contient et ce que vous faites avec ce contenu: le problème est que vous n'avez initialisé que deux des pointeurs du tableau. La lecture de la valeur et le fait de passer par les pointeurs non initialisés entraînent un comportement indéfini.

Voici une façon correcte de parcourir uniquement les éléments initialisés, en vous appuyant sur le fait que vous avez initialisé les deux premiers:

std::array<char*, 10> m_arr{}; // value initialisation
...
for(size_t i {0}; i < m_arr.size() && m_arr[i]; i++) {

// or with range-for:
for (char* ptr : m_arr) {
    if (!ptr)
        break;
    std::cout << ptr << '\n';

Une autre approche consiste à initialiser les autres pointeurs à null, et à vérifier cela dans la condition de boucle:

for(size_t i {0}; i < 2; i++) {


0 commentaires

0
votes

Je suis plus fan de ce type d'itération:

std::array<char*, 10> m_arr {};

N'oubliez pas d'initialiser votre tableau aussi, cela vous évitera quelques défauts de segmentation:

#include <iostream>
#include <array>
using namespace std;
// ...
for (auto&& object : m_arr)
{
    cout << (object != nullptr ? object : "Null pointer") << endl;
}


1 commentaires

@Blastfurnance Mon erreur, vous avez raison. Je vais ajouter ma réponse