9

I have an object whose constructor gets passed a parameter. If I know the parameter value at compile time, I can construct the object statically:

static FOOOBJ foo(3);

(I understand that it isn't really done statically, i.e. by the compiler, but is actually done during setup).

But if I don't know the parameter value at compile time, I'd still like to pre-allocate space for the object but construct the object in that space at run time. Can it be done without a separate .initialize() method?

JRobert
  • 15,397
  • 3
  • 24
  • 51

2 Answers2

4

You can use placement syntax to specify an existing allocation in which to instantiate the class.

FOOOBJ foo(0);

 ...

  FOOOBJ *f = new (foo) FOOOBJ(3);
Ignacio Vazquez-Abrams
  • 17,723
  • 1
  • 28
  • 32
3

Using an initialize() method to a class is contrary to the principle of a class constructor, i.e. once a class instance has been constructed, it should be "ready to use".

As suggested by Ignacio's answer, C++ placement syntax is much better for your purpose.

However, with Arduino libraries, placement syntax is not supported "out of the box", so you have to implement it yourself; don't fear, that is quite straightforward:

void* operator new(size_t size, void* ptr)
{
    return ptr;
}

Placement syntax can be a complex beast in C++, but for your specific purpose, its usage can be rather simple:

static char buffer[sizeof FOOOBJ];
static FOOOBJ* foo;

void setup() {
    ...
    foo = new (buffer) FOOOBJ(3);
    ...
}

The difference with your current code is that foo is now a pointer, hence any method call will use -> instead of ..

If you absolutely want to keep using foo as an instance and not a pointer, then you can do it (but I don't advise it as explained later) by using a reference instead:

static char buffer[sizeof FOOOBJ];
static FOOOBJ& foo = *((FOOOBJ*) buffer);

void setup() {
    ...
    new (buffer) FOOOBJ(3);
    ...
}

The problem with this code, is that you cannot know if foo has already been constructed with a real FOOOBJ instance or not; using a pointer, you can always check if it is 0 or not.

Using placement syntax, you must be aware that you cannot delete the foo instance above. If you want to destroy foo (i.e. ensure that its destructor is called), then you have to explicitly call the destructor:

foo->~FOOOBJ();
jfpoilpret
  • 9,162
  • 7
  • 38
  • 54