Russian Qt Forum

Программирование => С/C++ => Тема начата: Karl-Philipp от Январь 27, 2010, 18:59



Название: инициализация безразмерного массива в ст
Отправлено: Karl-Philipp от Январь 27, 2010, 18:59
Всем привет!
Есть такая структура
Код
C++ (Qt)
struct TableDescriptor {
   QString tableName;
   QString header[];
   int hiddenColumn[];
};

Хочется инициализировать структуру как-то так:
Код
C++ (Qt)
TableDescriptor tableMachines = {"machines", {"Id","Machine Name","Power","Speed", QString::null}, {0}};
в ответ компилятор ругается:
error: too many initializers for 'QString [0 ] '
error: too many initializers for 'int [0 ]'
Подскажите, пожалуйста, как правильно сделать?


Название: Re: инициализация безразмерного массива в ст
Отправлено: niXman от Январь 27, 2010, 19:06
упс..


Название: Re: инициализация безразмерного массива в ст
Отправлено: Rcus от Январь 27, 2010, 19:21
Размер струтуры должен быть известен во время компиляции, поэтому использовать безразмерные массивы как часть структуры не получится. Нужно вам хранить POD в струтурированном виде так и делайте так. Посмотрите как в ядре сделано: либо терминирование 0, либо запись размера массива рядом с указателем на содержимое.


Название: Re: инициализация безразмерного массива в ст
Отправлено: BRE от Январь 27, 2010, 19:37
Как вариант:
Код
C++ (Qt)
typedef QList<int> IntList;
struct TableDescriptor    
{                          
       TableDescriptor( const QString &tn, const QStringList &hdr, const IntList &hc ) :
               tableName( tn ), header( hdr ), hiddenColumn( hc )                      
       {                                                                                
       }                                                                                
 
       QString         tableName;
       QStringList     header;  
       IntList         hiddenColumn;
};                                  
 
...
 
TableDescriptor tableMachines( "machines", QStringList() << "Id" << "Machine Name" << "Power" << "Speed", IntList() << 1 << 2 );
 


Название: Re: инициализация безразмерного массива в с&#
Отправлено: Karl-Philipp от Январь 27, 2010, 20:17
спасибо всем :)

Размер струтуры должен быть известен во время компиляции, поэтому использовать безразмерные массивы как часть структуры не получится. Нужно вам хранить POD в струтурированном виде так и делайте так. Посмотрите как в ядре сделано: либо терминирование 0, либо запись размера массива рядом с указателем на содержимое.
последнее встречал в литературе. Интересно, а где именно это в ядре, подскажите, куда копать? Захотелось посмотреть :)


Название: Re: инициализация безразмерного массива в ст
Отправлено: Tonal от Январь 28, 2010, 08:37
Часто можно встретить такой трюк:
Код:
struct TableDescriptor {
    QString tableName;
    char header[1];
};
TableDescriptor* f(const QString &tableName, const char header[]) {
  TableDescriptor* ret = static_cast<TableDescriptor*>(
    ::operator new char(sizeof(TableDescriptor) + strlen(header)));
  ret->tableName = tableName
  strcpy(ret->header, header);
  return ret;
}
Некоторые компиляторы допускают не указывать размер в последнем члене массиве, если предполагается использовать эту технику (нестандартно).
Да, такой массив может быть только последний и только один (догадайся почему). :)
Кроме того, типы с нетривиальными деструкторами там хранить не рекомендуется (догадайся почему). :)
Массив из таких объектов создавать крайне не рекомендуется (догадайся почему). :)


Название: Re: инициализация безразмерного массива в ст
Отправлено: Karl-Philipp от Январь 28, 2010, 12:07
Tonal, не осилил :)
давайте пройдемся по методу f:
1) передаем в него ссылку на QString и массив символов неопределенной длины;
2) создаём символ char и инициализируем его числом, состоящим из суммы размера структуры и размера передаваемого массива (я почему-то подумал, что тут квадратные скобки нужны для создания массива символов заданной длины :-\)
3) самое сложное: преобразовываем символ со значением (числом) в структуру;
(у Страуструпа говорится "static_cast осуществляет преобразование родственных типов, например указателя на один тип к указателю на другой тип из той же иерархии классов, целый тип в перечисление... ". А здесь получается преобразование символа в структуру)
Правильно ли я понял?

Ответы на вопросы:
1. Не нашёл ответ!
2. Возможно потому, что данные деструкторы не будут вызываться в нужное время.
3. Возможно потому, что массив элементов константный. :)


Название: Re: инициализация безразмерного массива в ст
Отправлено: BRE от Январь 28, 2010, 16:09
Думаю, имелось ввиду следующее:
Код:
    ::operator new char[ sizeof(TableDescriptor) + strlen(header) ]

Но меня сильно смущает в этой структуре (TableDescriptor) объект класса QString (tableName). Конструктор по умолчанию для него не вызывается, думаю он нормально не сконструируется.


Название: Re: инициализация безразмерного массива в ст
Отправлено: Tonal от Январь 29, 2010, 09:31
Да, накосячил, таки давно серьёзно с плюсами не возился.
Правильная версия функции:
Код
C++ (Qt)
TableDescriptor* f(const QString &tableName, const char header[]) {
 TableDescriptor* ret = new (
   ::operator new (sizeof(TableDescriptor) + strlen(header))
   //new char[sizeof(TableDescriptor) + strlen(header)] //можно и так :)
 ) TableDescriptor;
 ret->tableName = tableName
 strcpy(ret->header, header);
 return ret;
}
 
Собственно такие трюки очень распространены в чистом С с его POD структурами. Вот я и забыл про конструктор. :)

2 terlan всё происходит так:
1. Принимаем параметры.
2. Выделяется память в размере sizeof(TableDescriptor) + strlen(header).
3. В ней конструируется объект TableDescriptor (размещаюший new - placement new).
4. В орбъекте заполняются значения полей. (почему влезет header понятно?)

Удаляется такой объект стандартным delete вполне корректно. :)
Но в С++ есть более удобные способы хранить массивы - например как std::vector. Поэтому подобная техника применяется либо для совместимости с чистым С или железом, либо для каких-то суровых оптимизаций работы с памятью.
Хотя в последнем случае правильный менеджер кучи скорее всего даст больший эффект без этих заморочек. :)


Название: Re: инициализация безразмерного массива в ст
Отправлено: Karl-Philipp от Январь 29, 2010, 15:25
Цитата: Tonal
...4. В орбъекте заполняются значения полей. (почему влезет header понятно?)...
понятно, вроде бы. Мы же выделили выделили место под структуру (с учетом размера передаваемого в функцию массива). Однако член структуры char header[1] можно инициализировать большим количеством элементов, чем заявлено.
Вот тут-то возник вопрос, если строка символов (в структуре) содержит 1 элемент, как разместятся другие элементы? Строка же у нас строго ограничена '\0' :)
Экспериментирую!