Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A library protocol for dynamically-sized objects

1 view
Skip to first unread message

Mathias Gaunard

unread,
Jan 21, 2009, 1:51:11 PM1/21/09
to
The C++ construction model of objects doesn't allow dynamically-sized
objects, which restricts how optimal in terms of compactness, memory
usage, locality and efficiency certain objects can be.

I thus propose a fairly simple library protocol so that one can design
dynamically-sized objects. Any help to better the system would be
appreciated.

The idea is simple: if the type is dynamically-sized, then instead of
using sizeof to know how much memory to allocate and then calling the
constructor on it, a type-specific functor that returns the size of
the object and that takes the constructor arguments is called, then
memory is allocated, then the constructor is called.

To construct a dynamically-sized object T(arg1, ..., argN);, you would
write something like this:
void* p = ::operator new(dyn_sizeof<T>()(arg1, ..., argN)); // or
alloca or whatever you want
T* t = new(p) T(arg1, ..., argN);

And type T would specialize dyn_sizeof to be an appropriate functor.

Here is an example with a string type:

struct compact_string
{
template<typename N>
compact_string(const char (&s)[N]) : len(N);
{
memcpy(str, s, N);
}

compact_string(const char* s) : len(0)
{
for(size_t i=0; s[i]; i++)
{
str[i] = s[i];
len++;
}
}

compact_string(const char* s, size_t n) : len(n)
{
memcpy(str, s, n);
}

compact_string(const compact_string& s) : len(s.len)
{
memcpy(str, s.str, len);
}

compact_string& operator=(const compact_string& s)
{
if(s.len > len)
throw whatever;

len = s.len;
memcpy(str, s.str, len);
}

size_t size() const { return len; }
char& operator[](size_t i) { return str[i]; }
const char& operator[](size_t i) const { return str[i]; }

private:
size_t len;
char str[1];
};

template<> dyn_sizeof<compact_string>
{
template<typename N>
size_t operator()(const char (&s)[N]) { return sizeof(size_t) +
N; }

size_t operator()(const char* s) { return sizeof(size_t) + strlen
(s); }
size_t operator()(const char* s, size_t n) { return sizeof(size_t)
+ n; }
size_t operator()(const compact_string& s) { return sizeof(size_t)
+ s.size(); }
};

There are of course a few problems that need to be solved. One is to
not invoke undefined or unspecified behaviour, which this probably
does.
The other would be that sizeof should not work with dynamically-sized
objects, because if it does the objects might be constructed without
the proper amount of memory.

A macro to allocate on the stack would be quite useful:

DECLARE(compact_string, s, ("foo"));

would expand to

compact_string& s = *new(alloca(dyn_sizeof<compact_string>()("foo")))
("foo");
scope_destruct<compact_string> s_destruct(s);

with

template<typename T>
struct scope_destruct
{
scope_destruct(T& t_) : t(t_) {}
~scope_destruct() { t->~T(); }
private:
T& t;
};

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

0 new messages