Vulkan-hpp повторно интерпретирует класс нестандартной компоновки для другого класса. Это законно? - PullRequest
6 голосов
/ 11 июля 2019

Так что недавно я работал с Vulkan-Hpp (Официальные привязки C ++ Vulkan Api, Github Link ).

Глядя на источник, я обнаружил, что они создают классы-обертки вокруг нативных структур Vulkan (например, vk::InstanceCreateInfo обвивает VkInstanceCreateInfo). ( Примечание: оборачивание, не производное от )

При вызове нативного API Vulkan указатели на классы-оболочки reinterpret_cast вводятся в нативные структуры Vulkan. Пример использования vk::InstanceCreateInfo:

//definition of vk::InstanceCreateInfo
struct InstanceCreateInfo
{
    /*  member function omitted  */
private:
  StructureType sType = StructureType::eInstanceCreateInfo;
public:
  const void* pNext = nullptr;
  InstanceCreateFlags flags;
  const ApplicationInfo* pApplicationInfo;
  uint32_t enabledLayerCount;
  const char* const* ppEnabledLayerNames;
  uint32_t enabledExtensionCount;
  const char* const* ppEnabledExtensionNames;
};

//definition of VkInstanceCreateInfo
typedef struct VkInstanceCreateInfo {
    VkStructureType             sType;
    const void*                 pNext;
    VkInstanceCreateFlags       flags;
    const VkApplicationInfo*    pApplicationInfo;
    uint32_t                    enabledLayerCount;
    const char* const*          ppEnabledLayerNames;
    uint32_t                    enabledExtensionCount;
    const char* const*          ppEnabledExtensionNames;
} VkInstanceCreateInfo;

//And the usage where reinterpret_cast takes place
template<typename Dispatch>
VULKAN_HPP_INLINE ResultValueType<Instance>::type createInstance( const InstanceCreateInfo &createInfo, Optional<const AllocationCallbacks> allocator, Dispatch const &d )
{
  Instance instance;
  Result result = static_cast<Result>( d.vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkInstance*>( &instance ) ) );
  return createResultValue( result, instance, VULKAN_HPP_NAMESPACE_STRING"::createInstance" );
}

Итак, мой вопрос: vk::InstanceCreateInfo и VkInstanceCreateInfo - это два разных типа. Более того, VkInstanceCreateInfo - это стандартная компоновка, а vk::InstanceCreateInfo - нет (так как она имеет спецификаторы смешанного доступа). reinterpret_cast находится между указателем этих двух типов (как сделано Vulkan-Hpp) законно? Это нарушает строгое правило алиасинга ?


Примечание: вы можете предположить, что VkInstanceCreateFlags и vk::InstanceCreateFlags являются взаимозаменяемыми в этом случае (в противном случае это сделало бы мой вопрос рекурсивным)

1 Ответ

4 голосов
/ 11 июля 2019

Что касается стандарта, то да, доступ к объекту vk::InstanceCreateInfo через указатель на объект VkInstanceCreateInfo нарушает строгое псевдоним.И это все равно нарушило бы строгий псевдоним, даже если оба типа были стандартным макетом с эквивалентным макетом.Стандарт не позволяет вам просто притворяться, что один тип класса является другим, даже если они имеют эквивалентные макеты.

Так что этот код опирается на поведение, специфичное для реализации.

неправильно?Будет ли дополнительная копия для каждого вызова функции интерфейса Vulkan заставлять вас чувствовать себя лучше, даже если это будет работать без него?В конечном счете, вам решать, сколько UB вам хочется терпеть.

...