M
Marcel Müller
From time to time I could use objects that consist of a header and an
array of items of immutable size. Doing this with two allocations is
straight forward, but has the drawback of another indirection on each
array member access and, of course, the additional allocation.
So the basic idea is to allocate the storage at once. Nothing special to
a C programmer. But wrapping this in a C++ class seems a little bit
tricky to me.
I use a simple string as an example. The string length is the header in
this case, the characters are the items. But I have other similar use
cases with more complex headers and items, like the nodes o a B-tree.
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
class String
{private:
size_t Len; // Logically const, but since we initialize it
// before constructor it has to be non-const.
private: // pure reference type => non-copyable
String(const String&);
void operator=(const String&);
private: // Avoid array creation and ordinary new operator!
static void* operator new(size_t);
static void* operator new[](size_t);
static void operator delete[](void*);
private: // allocators
static void* operator new(size_t s, size_t l)
{ String* that = (String*)new char[s+l+1];
that->Len = l; // Dirty early construction
return that;
}
public:
static void operator delete(void* p)
{ delete[] (char*)p; }
private:
String(const char* str)
{ memcpy(this+1, str, Len);
((char*)(this+1))[Len] = 0;
}
public:
static String* create(const char* str, size_t len)
{ return new (len) String(str); }
/// Return the current strings length.
size_t length() const
{ return Len; }
/// Return the current strings content.
const char* str() const
{ return (char*)(this+1); }
};
int main(int argc, char** argv)
{
String* mystr = String::create(argv[0], strlen(argv[0]));
printf("Len = %u, String = %s\n", mystr->length(), mystr->str());
delete mystr;
return 0;
}
The basic requirement is that operator new and constructor is now one
logical action. Are the common patterns to implement this?
From my point of view the access to members from operator new is really
dirty. And I am unsure whether the result of operator new is necessarily
equivalent to this.
Any better ideas?
Marcel
array of items of immutable size. Doing this with two allocations is
straight forward, but has the drawback of another indirection on each
array member access and, of course, the additional allocation.
So the basic idea is to allocate the storage at once. Nothing special to
a C programmer. But wrapping this in a C++ class seems a little bit
tricky to me.
I use a simple string as an example. The string length is the header in
this case, the characters are the items. But I have other similar use
cases with more complex headers and items, like the nodes o a B-tree.
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
class String
{private:
size_t Len; // Logically const, but since we initialize it
// before constructor it has to be non-const.
private: // pure reference type => non-copyable
String(const String&);
void operator=(const String&);
private: // Avoid array creation and ordinary new operator!
static void* operator new(size_t);
static void* operator new[](size_t);
static void operator delete[](void*);
private: // allocators
static void* operator new(size_t s, size_t l)
{ String* that = (String*)new char[s+l+1];
that->Len = l; // Dirty early construction
return that;
}
public:
static void operator delete(void* p)
{ delete[] (char*)p; }
private:
String(const char* str)
{ memcpy(this+1, str, Len);
((char*)(this+1))[Len] = 0;
}
public:
static String* create(const char* str, size_t len)
{ return new (len) String(str); }
/// Return the current strings length.
size_t length() const
{ return Len; }
/// Return the current strings content.
const char* str() const
{ return (char*)(this+1); }
};
int main(int argc, char** argv)
{
String* mystr = String::create(argv[0], strlen(argv[0]));
printf("Len = %u, String = %s\n", mystr->length(), mystr->str());
delete mystr;
return 0;
}
The basic requirement is that operator new and constructor is now one
logical action. Are the common patterns to implement this?
From my point of view the access to members from operator new is really
dirty. And I am unsure whether the result of operator new is necessarily
equivalent to this.
Any better ideas?
Marcel