Как обнулить элементы массива, если мой компилятор не соответствует стандарту

Мой компилятор (C++Builder6) синтаксически разрешает инициализацию элемента массива (по крайней мере, нулем), но на самом деле он этого не делает. Таким образом, утверждение в приведенном ниже примере терпит неудачу в зависимости от контекста.

#include <assert.h>

struct TT {
    char b[8];
    TT(): b() {}
};

void testIt() {
    TT t;
    assert(t.b[7] == 0);
}

Изменение компилятора на данный момент не вариант. Мой вопрос: каков будет лучший способ «исправить» этот недостаток в отношении будущей переносимости и соответствия стандартам?


Изменить: Как оказалось, мой первый пример был слишком коротким. Он упустил момент, что уровень заполнения массива настолько важен, что его нужно хранить очень близко к массиву, то есть: в том же классе.

Даже если исходная проблема остается, моя реальная проблема обычно такова:

struct TT2 {
    int size;
    char data[8];
    // ... some more elements
    TT2(): size(0), data() {}
    // ... some more methods
};

person Wolf    schedule 11.11.2013    source источник
comment
qc.embarcadero.com/wc/qcmain.aspx?d=83751 показывает, что это исправлено в более новых версиях (начиная с XE), и показывает обходной путь с использованием boost::value_initialized   -  person    schedule 11.11.2013
comment
@hvd: я думаю, что предложение boost::value_initialized было бы хорошим обычным ответом. Конечно, в исходниках он несколько тяжеловат, но поскольку работа ограничивается объявлением, мне кажется, что пока это лучший вариант.   -  person Wolf    schedule 11.11.2013
comment
Конечно. Я сделаю это, когда смогу проверить, что на самом деле работает, а что нет, но это произойдет не раньше чем через несколько часов.   -  person    schedule 11.11.2013
comment
На самом деле, я не могу заставить C++Builder 6 даже скомпилировать это. Он не принимает синтаксис : b(), жалуясь на вызов функции «b» без прототипа.   -  person    schedule 12.11.2013
comment
@hvd: Спасибо за ваши усилия. Я применил патч4 BCB6, может быть, это имеет значение? bcc32 --version говорит Borland C++ 5.6.4 für Win32 Copyright (c) 1993, 2002 Borland при моей установке.   -  person Wolf    schedule 12.11.2013


Ответы (3)


Я думаю, вы можете использовать это:

TT() { std::fill(b, b + 8, char()); }

Таким образом, вы решите свою проблему, пока все в порядке с переносимостью и соответствием стандартам!

person BigBoss    schedule 11.11.2013
comment
Пока компилятор соблюдает инициализацию значения char(). Явный 0 может быть безопаснее. - person Mike Seymour; 11.11.2013
comment
@MikeSeymour Вопрос о стандарте и будущем соответствии, инициализация значения является частью стандарта, поэтому я думаю, что char() более стандартен, чем литерал int 0! - person BigBoss; 20.11.2013
comment
Вопрос касается компилятора, который не соответствует стандарту; в частности, тот, в котором инициализация значения нарушена. В этом случае я бы вообще избегал инициализации значений, даже если бы заметил, что в этом случае это работает. - person Mike Seymour; 20.11.2013
comment
Невозможно избежать инициализации значения, когда у вас есть константные или ссылочные элементы, а BCB6 не хватает только инициализации элементов массива. У меня так много кода, который так сильно зависит от правильной инициализации простых элементов (с использованием синтаксиса ctr), что я абсолютно в этом уверен. - person Wolf; 23.11.2013

Вы можете использовать fill_n, как это предлагается в: Инициализация C/C++ обычного массива с одним значением по умолчанию

Если fill_n недоступен, вы всегда можете использовать memset, например:

TT() {memset(b, 0, sizeof b);}
person jcm    schedule 11.11.2013
comment
Как и в примере BigBoss std::fill, мне не нравится дублировать литерал размера. - person Wolf; 11.11.2013
comment
@WolfP. Если вы не хотите дублировать литерал размера, вы можете получить размер массива: (sizeof b / sizeof b[0]); - person jcm; 11.11.2013
comment
Да, это NELEMS ;) ...теперь вы видите потенциал дублирования для каждого члена. Это действительно ужасно, как долго эта ошибка существовала в BCB. - person Wolf; 11.11.2013
comment
@WolfP. Что ж, я полагаю, что стандартный способ С++ 11 не вариант, поскольку вы работаете с C++ Builder6, поэтому я бы предложил использовать шаблон для получения размера массива: template <typename T, size_t N> size_t arsize( T (&ar)[N] ) {return N;} тогда вы должны иметь возможность использовать memset(b,0,arsize(b)); - person jcm; 11.11.2013
comment
Интересная статья о получении количества элементов в массиве: blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx - person jcm; 11.11.2013
comment
Интересно читать :) ... но в смысле вступительного вопроса я бы предпочел шаблонное решение для этого, чем только для его части - person Wolf; 11.11.2013
comment
@WolfP. Извините, но я не совсем понимаю, что вы имеете в виду, говоря только о части. Если вам нужен шаблон, который инициализирует 0 всех элементов из полученного массива, вы можете изменить предыдущий код на: template <typename T, size_t N> size_t initarray( T (&ar)[N] ) { memset(array, 0, N*sizeof(T)); }. Но, скорее всего, я что-то не так понимаю. - person jcm; 12.11.2013
comment
Я бы предпочел ограничить изменения точкой объявления, возможно, используя своего рода template <typename T, size_t size> class Array { /*...*/ }; Тогда не было бы необходимости в явной инициализации в блоках ctr (мне приходится обрабатывать более одного класса). Поскольку задано size, я могу вычислить размер массива по (sizeof (T) * size) или использовать size напрямую, как в ответе BigBoss, и я делаю это только один раз: в определении шаблона. Кстати: ваше текущее определение размера (sizeof b / sizeof b[0]) не является правильным количеством байтов для memset . - person Wolf; 12.11.2013
comment
Вы правы насчет количества байтов для memset, на самом деле sizeof b должно быть достаточно. Я просто обновил его таким образом по ошибке, потому что мы обсуждали количество элементов в массиве. С другой стороны, в моем первоначальном предложении размер уже использовался напрямую, но вы жаловались на дублирование литерала размера, поэтому я предложил способ автоматического получения количества элементов в массиве. Бесстрашный, если создание шаблона массива подходит для вас, вы можете расширить предыдущее предложение для его достижения. - person jcm; 12.11.2013

Я хотел бы добавить к предыдущим сообщениям, что если вы используете массив символов в качестве строки, то достаточно написать в конструкторе

TT() { b[0] = '\0'; }

person Vlad from Moscow    schedule 11.11.2013
comment
Да, это правда, но выбор char в моем примере, возможно, был ошибкой; строки уже реализованы с использованием AnsiString или std::string. - person Wolf; 11.11.2013