Re: allocate memory 'inside' POD
On Tuesday, April 3, 2012 8:33:40 PM UTC+2, Thomas Mang wrote:
Hi,
Consider the need for a POD-struct which can store a given number of
double values, where this number is determined at run-time (though then
fixed). The struct itself must not use a pointer type. Access to the
double values shall be possible through members of the POD; moreover,
each POD instance and its associated double values shall cover
contiguous memory; if there is an array of these PODs then the whole
array shall also be in contiguous memory (if you wonder why all that
mess: constraints in a highly heterogeneous environment with multiple
languages and hence compatibility issues).
The snippet below does the job practically speaking, but I am afraid
it's not guaranteed to work according to C++98 / C++03 (these my
implementations refer to). I think that in foo the member 'vals' should
be appropriately aligned so it matches alignment requiresments of a
double array indepenent of the number of elements the array has.
However, according to 5.7/5 I would not be allowed to increment a
pointer to the first element of 'vals' more than once if thispointer has
been obtained through someFoo.vals.
I dunno. What if you had vals[1000] instead? Would it be valid then?
I could treat the bytes at vals and beyond as an array of doubles, but
according to 3.8/2 it seems that a single memory region can only be of
one type at a time; if it's the vals member of a foo object than I can
access it but can't increment the pointer to reach all elements; if it's
interpreted as an array of doubles then technically there would be no
foo object any more and I would not be allowed to access it through the
foo interface.
That's true, I guess.
However, what you want is a variable-element-number array, and people are doing it on various implementations. In fact, you might oftentimes see std::string implemented like that (only one buffer for all data, chars included + copy-on-write).
Here's an implementation that might work.
template<typename t>
struct vararr
{
const size_t len;
t data[1];
static vararr* create(size_t s) { return new (s) vararr(s); }
~vararr() { std::for_each(p1(), p1()+(len-1), &destruct); }
void operator delete(void* p, size_t cElems) { delete [] static_cast<char*>(p); }
private:
t* p1() { return &data[1]; }
vararr(size_t s) : len(s)
{
t* p = p1();
t* pEnd = p1() + len - 1;
try
{
while(p != pEnd)
{
new (p) t;
p++;
}
}
catch(...)
{
while (--p >= p1())
destruct(*p);
throw;
}
}
static void destruct(t& item)
{
item.t::~t();
}
void* operator new(size_t s, size_t cElems)
{
return new char[s + sizeof t * (cElems-1)];
}
};
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]