Cześć!
W jaki sposób poprawnie dogadać się w kodzie C++ z tzw. Flexible Array Member ze standaru C?
API z C oczekuje ode mnie wypełniania struktur z takimi paskudami i muszę jakoś to obsłużyć.
Miałem na początku zagwozdkę, jak w ogóle podejść do tematu: jak stworzyć i przypisać wartości do obiektu takiej struktury?
Wykoncypowałem na tę chwilę taki wrapper, który zajmuje się podstawowym zarządzaniem pamięcią dla tego ustrojstwa, ale nie mam przekonania, czy nie dotykam Undefined Behavior przy dostępie do elementów takiej tablicy.
Przykład:
// main.cpp
#include "FlexibleArrayMemberWrapper.hpp"
extern "C"
{
// structure with FAM from C API:
typedef struct
{
double ordinary_member_d;
int flexible_array_member[];
} c_struct_with_fam;
}
int main()
{
c_struct_with_fam bar;
bar.ordinary_member_d = 3.14;
// bar.flexible_array_member = new int[3]; // (1)
FlexibleArrayMemberWrapper<c_struct_with_fam, int> foo{3};
foo.get().ordinary_member_d = 3.14;
foo.get().flexible_array_member[0] = 100;
foo.get().flexible_array_member[1] = 200; // (2)
foo.get().flexible_array_member[2] = 300;
}
// FlexibleArrayMemberWrapper.hpp
#pragma once
#include <cstdlib>
#include <new>
template <typename struct_t, typename array_t>
class FlexibleArrayMemberWrapper
{
public:
FlexibleArrayMemberWrapper(const FlexibleArrayMemberWrapper &) = delete;
FlexibleArrayMemberWrapper(FlexibleArrayMemberWrapper &&) = delete;
void operator=(const FlexibleArrayMemberWrapper &) = delete;
explicit FlexibleArrayMemberWrapper(size_t numberOfElements)
: data{nullptr}
{
const auto memory = std::malloc(getSize(numberOfElements));
if (memory == nullptr)
{
throw std::bad_alloc{};
}
this->data = reinterpret_cast<struct_t *>(memory);
}
~FlexibleArrayMemberWrapper()
{
if (data != nullptr)
{
std::free(data);
}
}
struct_t &get()
{
return *this->data;
}
private:
struct_t *data;
constexpr static size_t getSize(size_t numberOfElements)
{
constexpr auto structureTypeSize = sizeof(struct_t);
constexpr auto arrayTypeSize = sizeof(array_t);
return arrayTypeSize * numberOfElements + structureTypeSize;
}
};
(1) - to było moje pierwsze naiwne podejście do przypisania wartości dla FAM
(2) - trochę mi to pachnie UB
Czy ktoś miałby może jakieś porady w tej kwestii, spotkał się z takim zapotrzebowaniem? Wszystko co udało mi się znaleźć traktuje o propozycjach dorzucenia FAM do standardu C++.