8

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?

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();
  • 1
    I wasn't aware of the syntax but that makes total sense! Does the constructor need to be aware of / designed for it? FOOOBJ is a OneWire object, using Jim Studt's library (v2.2). I'm getting the message error: no matching function for call to 'operator new(unsigned int, byte [14])' on the new call. It looks like avr-g++ may not understand the syntax. – JRobert May 14 '14 at 18:58
  • Yes, you're right, I'm using Eclipse for my Arduino projects and what I checked it, it seemed to work, except that what worked was Eclipse C++ compilation, not avr-g++! I have edited my answer to show a simple workaround. – jfpoilpret May 14 '14 at 19:30
  • Regarding your question on constructor, ther is no specific requirement, but if the constructor itself performs dynamic allocation, then placement new will not prevent it. – jfpoilpret May 14 '14 at 19:32
  • I'm also using Eclipse - what C++ compiler is yours configured with? Plus looking at the OneWire constructor, it doesn't new anything, it just initializes some i/o. – JRobert May 14 '14 at 21:09
  • I'm using Eclipse with eclipse.baeyens.it plugin (which uses Arduino IDE tools, ie avr-g++ + Arduino libs); but the C++ compilation occurs on-the-fly with Eclipse C++, and uses avr-g++ only when launching the Arduino build. I had not checked the latter step initially. – jfpoilpret May 15 '14 at 3:43
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);
  • I'd suggest to replace the declaration of foo with char foo[sizeof FOOOBJ]; so that FOOOBJ constructor does not get called for foo which could be a real problem depending on what the constructor does. – jfpoilpret May 10 '14 at 5:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.