Re: allocate memory 'inside' POD
Am 04.04.2012 19:21, schrieb goran.pusic@gmail.com:
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;
I strongly suggest ensure that the global placement new is called here
by writing instead
::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)];
The grammar does not allow to provide a type-id without parentheses to
the sizeof operator:
sizeof unary-expression
sizeof ( type-id )
So you need to write "sizeof (t)" instead of "sizeof t"
}
};
Above implementation is broken as of core language defect
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#429
The reason is that you have a placement allocation function, but your
deallocation function with the signature
void operator delete(void* p, size_t cElems)
According to [basic.stc.dynamic.deallocation] p2:
"If class T [..] does declare a member deallocation function named
operator delete with exactly two parameters, the second of which has
type std::size_t (18.2), then this function is a usual deallocation
function."
This leads to the problem described in CWG issue 429.
To fix this problem it seems better to make destructor and operator
delete private and use a tag type for proper discrimination. Then,
provide a public destroy function. E.g.:
struct stub {};
template<typename t>
struct vararr
{
const size_t len;
t data[1];
static vararr* create(size_t s)
{
return new (s, stub()) vararr(s);
}
static void destroy(vararr* pv)
{
if (pv)
{
pv->~vararr();
operator delete(pv, size_t(), stub());
}
}
private:
~vararr() { std::for_each(p1(), p1()+(len-1), &destruct); }
void* operator new(size_t s, size_t cElems, stub)
{
return ::new char[s + sizeof(t) * (cElems-1)];
}
void operator delete(void* p, size_t cElems, stub)
{
::delete [] static_cast<char*>(p);
}
//... As before
};
You can simplify even further when the tag type is used to transport the
relevant information directly. E.g.
struct size_tag
{
const size_t n;
size_tag(size_t n) : n(n) {}
};
template<typename t>
struct vararr
{
const size_t len;
t data[1];
static vararr* create(size_t s)
{
return new (size_tag(s)) vararr(s);
}
static void destroy(vararr* pv)
{
if (pv)
{
pv->~vararr();
operator delete(pv, size_tag(0));
}
}
private:
~vararr() { std::for_each(p1(), p1()+(len-1), &destruct); }
void* operator new(size_t s, size_tag cElems)
{
return ::new char[s + sizeof(t) * (cElems.n-1)];
}
void operator delete(void* p, size_tag)
{
::delete [] static_cast<char*>(p);
}
//... As before
};
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]