On Fri, 24 Feb 2023 at 09:50, Jonathan Wakely <jwak...@redhat.com> wrote: > > On Fri, 24 Feb 2023 at 09:49, Jakub Jelinek wrote: > > > > Assuming a compiler handles the T m_vecdata[1]; as flexible array member > > like (which we need because standard C++ doesn't have flexible array members > > nor [0] arrays), I wonder if we instead of the m_auto followed by m_data > > trick couldn't make auto_vec have > > alignas(vec<vl_embed>) unsigned char buf m_data[sizeof (vec<vl_embed>) + (N > > - 1) * sizeof (T)]; > > and do a placement new of vec<vl_embed> into that m_data during auto_vec > > construction. Isn't it then similar to how are flexible array members > > normally used in C, where one uses malloc or alloca to allocate storage > > for them and the storage can be larger than the structure itself and > > flexible array member then can use storage after it? > > You would still be accessing past the end of the > vec<vl_embed>::m_vecdata array which is UB.
My thinking is something like: // New tag type struct vl_relative { }; // This must only be used as a member subobject of another type // which provides the trailing storage. template<typename T> struct vec<T, va_heap, vl_relative> { T *address (void) { return (T*)(m_vecpfx+1); } const T *address (void) const { return (T*)(m_vecpfx+1); } alignas(T) alignas(vec_prefix) vec_prefix m_vecpfx; }; template<typename T, size_t N /* = 0 */> class auto_vec : public vec<T, va_heap> { // ... private: vec<T, va_heap, vl_relative> m_head; T m_data[N]; static_assert(...); };