Какой безопасный способ для заполнения многомерного массива, используя std :: fill? - PullRequest
11 голосов
/ 16 октября 2010

Вот что я использую:

class something
{
    char flags[26][80];
} a;

std::fill(&a.flags[0][0], &a.flags[0][0]+26*80, 0);

(Обновление: я должен был прояснить ранее, что я использую это внутри класса.)

Ответы [ 4 ]

18 голосов
/ 16 октября 2010

Простой способ инициализации массива 0 находится в определении:

char flags[26][80] = {};

Если вы хотите использовать std::fill или сбросить массивЯ нахожу это немного лучше:

char flags[26][80];
std::fill( &flags[0][0], &flags[0][0] + sizeof(flags) /* / sizeof(flags[0][0]) */, 0 );

fill, выраженный в терминах размера массива, позволит вам изменить размеры и сохранить fill нетронутым.sizeof(flags[0][0]) - это 1 в вашем случае (sizeof(char)==1), но вы можете оставить его там, если хотите изменить тип в любой точке.

В этом конкретном случае (массив flags - встроенный тип) Я мог бы даже рассмотреть возможность использования memset, даже если это наименее безопасный вариант (он сломается, если тип массива будет изменен на не-тип pod):

memset( &flags[0][0], 0, sizeof(flags) );

Обратите внимание, что во всех трех случаях размеры массивов вводятся только один раз, а остальное выводит компилятор.Это немного безопаснее , поскольку оставляет меньше места для ошибок программиста (измените размер в одном месте, забудьте о нем в других).

РЕДАКТИРОВАТЬ: Вы обновили код и какон не скомпилируется, так как массив является частным, и вы пытаетесь инициализировать его извне.В зависимости от того, является ли ваш класс агрегатом (и хотите ли вы сохранить его как таковой) или хотите ли вы добавить конструктор в класс, вы можете использовать различные подходы.

const std::size_t rows = 26;
const std::size_t cols = 80;
struct Aggregate {
   char array[rows][cols];
};
class Constructor {
public:
   Constructor() {
      std::fill( &array[0][0], &array[rows][0], 0 ); // [1]
      // memset( array, 0, sizeof(array) );
   }
private:
   char array[rows][cols];
};
int main() {
   Aggregate a = {};
   Constructor b;
}

Даже если arrayдолжен быть общедоступным, лучше использовать конструктор, поскольку он гарантирует, что array правильно инициализируется во всех экземплярах класса, в то время как внешняя инициализация зависит от того, что пользовательский код не забывает устанавливать начальные значения.

[1] Как упомянул @Oli Charlesworth в комментарии, использование констант - это другое решение проблемы необходимости указывать (и поддерживать синхронизацию) размеры в нескольких местах.Я использовал этот подход здесь с другой комбинацией: указатель на первый байт вне двумерного массива может быть получен путем запроса адреса первого столбца на одну строку за пределами двумерного массива.Я использовал этот подход только для того, чтобы показать, что это возможно, но он не лучше, чем другие, такие как &array[0][0]+(rows*cols)

2 голосов
/ 16 октября 2010

это безопасно, двумерный массив - это массив массивов. Поскольку массив занимал смежные хранилища, то и многомерная вещь тоже будет. Так что да, все в порядке, безопасно и портативно. Предполагая, что вы НЕ спрашиваете о стиле, который покрыт другими ответами (поскольку вы используете флаги, я настоятельно рекомендую std::vector<std::bitset<80> > myFlags(26))

0 голосов
/ 02 сентября 2018
char flags[26][80];
std::fill((char*)flags, (char*)flags + sizeof(flags)/sizeof(char), 0);
0 голосов
/ 16 октября 2010

Является ли char[80] заменой реального типа строки? В этом случае я рекомендую следующее:

std::vector<std::string> flags(26);
flags[0] = "hello";
flags[1] = "beautiful";
flags[2] = "world";
// ...

Или, если у вас есть компилятор C ++, который поддерживает списки инициализации, например, недавний компилятор g ++:

std::vector<std::string> flags { "hello", "beautiful", "world" /* ... */ };
...