Вложенное C выравнивание структур массива в Clang - PullRequest
3 голосов
/ 04 мая 2020

У меня небольшая проблема с памятью в C ++ 17 с использованием компиляции Clang для x64. Так как я работаю с копиями памяти низкого уровня на специализированном оборудовании, я действительно зависим от того, как память выровнена, как ожидалось. Я недавно перешел из Visual Studio в Clang и столкнулся со следующей проблемой:

См. Следующий код:

struct ContainerRoot{};
template<size_t t_size, class t_type>
struct Container : public ContainerRoot
{
    t_type contents[t_size];
};

static_assert(sizeof(Container<1, double>) == 8);           //This works as expected
static_assert(sizeof(Container<4, double>) == 32);          //This works as expected
static_assert(sizeof(Container<16, double>) == 128);        //This works as expected
static_assert(sizeof(Container<4, Container<4, double>>) == 128); //This fails. 

В приведенном выше примере sizeof (Container ) на самом деле 136 (дополнительные 8 байт). Мой вопрос: почему добавляются дополнительные 8 байтов, и можно ли этого избежать? Я хотел бы использовать компилятор Clang, но если для этого нет обходного пути, возможно, не стоит переписывать весь код, связанный с отправкой этих данных на специализированное оборудование.

Пока что у меня есть проверено с использованием std :: is_polymorphi c >> () только для того, чтобы подтвердить, что в класс не было добавлено виртуальной таблицы поиска.

1 Ответ

3 голосов
/ 04 мая 2020

Цитирование ru.cppreference.com :

Размер любого объекта или дочернего подобъекта [...] должен быть не менее 1, даже если тип пустой тип класса (т. е. класс или структура, которые не имеют нестабильных c членов данных), чтобы иметь возможность гарантировать, что адреса различных объектов одного типа всегда различны.

Это ограничение не применяется к пустым базам (Оптимизация пустых баз).

Однако en.cppreference.com также отмечает:

Оптимизация пустых баз запрещена если один из пустых базовых классов также является типом или базой типа первого элемента данных, не относящегося к состоянию c, так как два базовых подобъекта одного и того же типа должны иметь разные адреса в представлении объекта самый производный тип.

Что, к сожалению, имеет место при работе с Container<4, Container<4, double>> в качестве первого члена, который имеет тип Container<4, double>, а также Container<4, Container<4, double>> оба наследуются от ContainerRoot. * 10 21 *

Таким образом, я бы выдвинул гипотезу, что MSV C в данном случае на самом деле ошибочна и преждевременно применяет оптимизацию, которую не должен делать.

...