Я предполагаю, что вы хотите, чтобы это компилировалось в режиме чистого C ++, и что вы не хотите просто компилировать некоторые файлы в C, а некоторые в C ++ и более поздние ссылки.
Предупреждениеговорит вам, что сгенерированный компилятором конструктор и присваивание копии, скорее всего, будут ошибаться в вашей структуре.Использование массивов нулевого размера в конце структуры - это, как правило, в C способ иметь массив, который определяется во время выполнения, но недопустим в C ++, но вы можете получить аналогичное поведение с размером 1:
struct runtime_array {
int size;
char data[1];
};
runtime_array* create( int size ) {
runtime_array *a = malloc( sizeof(runtime_array) + size ); // [*]
a->size = size;
return a;
}
int main() {
runtime_array *a = create( 10 );
for ( int i = 0; i < a->size; ++i ) {
a->data[i] = 0;
}
free(a);
}
Этот тип структур предназначен для динамического выделения - или с помощью хитрости динамического выделения стека - и обычно не копируется, но если вы попытаетесь, вы получите странные результаты:
int main() {
runtime_array *a = create(10);
runtime_array b = *a; // ouch!!
free(a);
}
В этом примере сгенерированный компилятором конструктор копирования выделит в стеке ровно sizeof(runtime_array)
байт, а затем скопирует первую часть массива в b
.Проблема в том, что b
имеет поле size
со значением 10, но вообще не имеет памяти для какого-либо элемента.
Если вы все еще хотите иметь возможность скомпилировать это в C, то вы должны разрешить предупреждениезакрыв глаза: молчите это конкретное предупреждение.Если вам нужна только совместимость с C ++, вы можете вручную отключить конструирование и назначение копирования:
struct runtime_array {
int size;
char data[1];
private:
runtime_array( runtime_array const & ); // undefined
runtime_array& operator=( runtime_array const & ); // undefined
};
Объявляя конструктор копирования и оператор присваивания, компилятор не сгенерирует его для вас (и не будет жаловаться на это.зная как).Имея два приватных, вы получите ошибки времени компиляции, если по ошибке попытаетесь использовать их в коде.Поскольку они никогда не вызываются, их можно оставить неопределенными - это также используется, чтобы не вызывать его из другого метода класса, но я предполагаю, что других методов нет.
Поскольку вы выполняете рефакторингв C ++ я бы также сделал конструктор по умолчанию частным и предоставил статический публичный встроенный метод, который позаботится о правильном распределении содержимого.Если вы также сделаете деструктор приватным, вы можете убедиться, что пользовательский код не пытается вызвать delete
для ваших объектов:
struct runtime_array {
int size;
char data[1];
static runtime_array* create( int size ) {
runtime_array* tmp = (runtime_array*)malloc(sizeof(runtime_array)+size);
tmp->size = size;
return tmp;
}
static void release( runtime_array * a ) {
free(a);
}
private:
runtime_array() {}
~runtime_array() {}
runtime_array( runtime_array const & ); // undefined
runtime_array& operator=( runtime_array const & ); // undefined
};
Это гарантирует, что пользовательский код не по ошибке создаст ваши объекты вне складывая и не смешивая вызовы malloc/free
с вызовами new/delete
, так как вы управляете созданием и уничтожением ваших объектов.Ни одно из этих изменений не повлияет на макет памяти ваших объектов.
[*] Расчет для размера здесь немного неправильный, и он будет перераспределяться, вероятно, на sizeof(int)
по сравнению с размером объектаимеет отступ в конце.