Правильный способ l oop через std :: array - PullRequest
0 голосов
/ 28 мая 2020

Рассмотрим следующий std :: array указателей на char:

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

Я знаю, что могу oop пройти через массив, используя следующий код

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

Но это Подход выдает исключение «Место чтения нарушения прав доступа», когда i-й элемент назначен неправильно. Например, следующий код назначает первые два элемента, но третий элемент, m_arr.at(3), вызывает вышеупомянутую ошибку:

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

Я нашел быстрое решение этой проблемы, проверив i-й элемент с помощью последний элемент массива, чтобы пропустить неназначенные элементы, но, очевидно, это не чистый ответ

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

Я считаю, что есть лучший способ l oop через этот массив и избежать ошибки. Заранее благодарю за помощь.

Ответы [ 3 ]

2 голосов
/ 28 мая 2020

Инициализируйте свой массив:

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

, тогда вы можете проверить безопасность для значения, отличного от nullptr:

for (auto ptr : m_arr) {
    if (ptr) std::cout << ptr << std::endl;
}
1 голос
/ 28 мая 2020

Проблема не столько в том, как вы перебираете массив, а скорее в том, что он содержит, и что вы делаете с этим содержимым: проблема в том, что вы инициализировали только два указателя в массиве. Чтение значения и косвенный переход через неинициализированные указатели приводит к неопределенному поведению.

Вот правильный способ l oop через только инициализированные элементы, полагаясь на знания, которые вы инициализировали первые два:

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

Другой подход - инициализировать другие указатели нулевым значением и проверить это в условии l oop:

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';
0 голосов
/ 28 мая 2020

Мне больше нравятся итерации этого типа:

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

Не забудьте также инициализировать свой массив, это избавит вас от некоторых ошибок сегментации:

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