Re: Question on use of "placement" new
letz@grame.fr wrote:
Hi,
We have a class whose objects are to be allocated in shared memory. To
do that a ShmManager base class is defined so that operator new and
delete are redefined to allocate segments in shared memory. A typical
class "Foo" then inherit from ShmManager to have this behaviour.
class ShmManager {
void* operator new(size_t size);
void operator delete(void* p, size_t size);
};
(...)
We are using the "placement" new syntax doing:
class Foo1 : public ShmManager
{
int fData1;
Barr fData2[]; // will be extented using "placement" new
};
ShmManager* ptr
= ShmManager::operator new(sizeof(Foo1) + num * sizeof(Barr));
Foo1* = new(ptr) Foo1();
So that Foo1 object nows gets a dynamic "num" number of elements. This
seems to work, but is this safe to do that? Are we obliged to put the
fData2 fied as the *last* element in the Foo1? Is there any better/
safer manner to implement the same pattern?
I do not like the solution where the flat data area starts "inside" the
object. I think you quite correctly point out that you would have to put
the element last and even then you're not really on the safe side.
I would rather place your fData2 member as a normal pointer inside the
object and have it reference memory just beyond the object. This way you
do not have to worry where your C++ implementation puts the fData2
member inside the object and its functionally still the same -- namely
that you have a "flat" object.
Also, there is the problem of telling the object how big the additional
memory is, which I've solved with a ctor taking the same argument as the
placement new.
I *think* my solution below is clearer, but note that this is the first
time I've ever done operator new/delete overloading so I may well have
overlooked something ...
[-- SAMPLE CODE --]
#include <memory>
#include <crtdbg.h>
class ShmMan {
// Use this as a base class, so make the operators protected
protected:
static void* operator new(size_t size) {
return ::malloc(size);
}
static void operator delete(void* p) {
::free(p);
}
};
class Flat : public ShmMan {
size_t datasize_;
char* data_;
private: // Explicitly disable the normal new operator
static void* operator new(size_t size);
public:
// provide matching pair of new and delete:
static void* operator new(size_t size, size_t datasize) {
return ShmMan::operator new(size + datasize);
}
static void operator delete(void* p, size_t datasize) {
ShmMan::operator delete(p);
}
public:
// *if* we want to have a default ctor, it should initialize the
// members to zero
Flat() : datasize_(0), data_(0) {};
// This ctor tells the object how big the additionally allocated
// memory is:
explicit Flat(size_t s) {
datasize_ = s;
// If this ctor is used, assume that there is sufficient
// memory allocated just "behind" this:
void* self = this;
void* beyond_self = static_cast<char*>(self) + sizeof(Flat);
data_ = static_cast<char*>(beyond_self);
memset(data_, 0, datasize_);
}
// assign data to our "flat" object:
void assign_data(const char* str) {
if(data_ && str) {
memcpy(data_, str, std::min(datasize_, strlen(str)));
data_[datasize_-1] = '\0';
}
}
// access the data
const char* get_data() {
return data_;
}
};
int main(int argc, char* argv[])
{
// tell me of memleaks:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
size_t dyn_size = 13;
std::auto_ptr<Flat> p2(new(dyn_size) Flat(dyn_size));
p2->assign_data("Hello World, this is a test!");
printf("<%s>\n", p2->get_data());
return 0;
}
[/-- SAMPLE CODE --]
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]