C++: Object instantiation in setup()

I need to instantiate an object in setup() rather than in the global scope as I need to calculate the value of one of its properties. I was hoping I could just have a pointer to it in global scope which I would assign in setup().

But if I do that, it'll be destroyed when setup() exits - I'm warned that that might happen by the error "taking address of temporary" when I try to assign its address to the global pointer. But I need to use it in loop().

Is there any way to define it as a persistent object so it can be referred to through the global pointer to it? Or any other work-around?

I suppose I could always dispense with loop() and put everything I'd want in it into a while (true) { } at the end of setup(), but that's doesn't seem to be how you're meant to write Arduino scripts. I could also modify the class to be able to define a vanilla object with its properties set later, but I'd rather not have to modify someone else's library.

Regards - Philip

Just declare the object as global and then initialize it in setup().

Ok, malloc is a problem in micro environments, but besides that, I would use

YourClass* gPtr;

void setup() {
  gPtr = new YourClass();
}

You could use “placement new” to “construct” an instance in a place (i.e. RAM address) that you choose. This storage could be declared at file scope, so that the object “lives” forever, but can be created or destroyed without calling the nasty new/malloc and free.

// The placement new is not normally defined, do it here
void *operator new( size_t size, void *ptr )
{
    return ptr;
}

static uint8_t objStorage[ sizeof(objType) ]; // RAM for the object

objType *obj; // a pointer to the object, once it's constructed

void setup()
{
  obj = new (objStorage) objType(...); // construct it in that place
}

void loop()
{
  obj->doSomething(); // now it can be used, through the pointer
}

However, it would be much better form to not do anything in the default constructor. Instead call a “begin” or “init” method… like Serial.begin, for instance:

objType obj; // default ctor does nothing

void setup()
{
  obj.begin();
}

void loop()
{
  obj->doSomething();
}

This latter technique is Strongly Recommended.

Cheers,
/dev

What's the real problem with using new? There's nothing wrong with it. Since you would allocate memory only at the beginning of the program and would not free it later, there is no possibility of fragmenting your memory, which I believe is the real issue some people take with dynamic memory.

(Dynamic memory allocation also uses a few more bytes of memory to keep track of each allocation, but is that a real problem? You decide.)

What's the real problem with using new? There's nothing wrong with it. Since you would allocate memory only at the beginning of the program and would not free it later, there is no possibility of fragmenting your memory, which I believe is the real issue some people take with dynamic memory.

For the most part, I agree with what you're saying. In itself, new/delete and dependents malloc/free are not intrinsically evil.

I do disagree with saying "some people take issue with the possibility fragmenting your memory". Any embedded developer, from an intermediate-level Arduino hacker, to the hard-core bare-metal cycle-nut, would take issue with memory fragmentation. Willy-nilly use will, inarguably and inevitably, lead to MF.

I sort of agree with allowing malloc "only at the beginning of the program", and never calling free. The key word is "only". If that's truly the only place it's used, the CPU won't be going up in flames.

OTOH, I sort of disagree, because this is a limited-resource environment, and being stingy is a good habit to have. Beginners rarely have that habit, or simply don't understand what using new/malloc costs:

  • extra bytes for chunk management (4 bytes/malloc + 4 bytes head?)
  • new (8 bytes), delete (8 bytes), malloc (268 bytes) and free (304 bytes) added to program space
  • the sketch executes something that could have been done at compile/link timeThese are relatively small prices to pay, unless you need those 600 bytes of flash.

Also, I think beginners who use it in setup can be tempted to use it naively elsewhere. It's just safer if you don't use it at all. Pre-allocated globals or even pools are always guaranteed to be predictably safe. I just never recommend malloc & friends.

Looking at it conversely, what do you gain?

Well, I'm sure this isn't the last discussion we'll ever have about dynamic memory allocation. :wink:

My $0.02,
/dev

OK thanks everyone. I’m aware of the theological and practical questions surrounding malloc() in an embedded environment and I didn’t want to go there - too many electrons have been harmed in that debate already. I’ll take the consequences if they materialise.

As I tried to explain, I can’t declare it in global and then initialise it in setup() as declaration performs instantiation, which requires a parameter I need to determine dynamically. Thank you /dev for the only solution that might actually serve my purposes, using placement, though I was hoping there might be a way within the language. And of course, I could hack the library defining the class to separate instantiation and initialisation, but since it’s not my library (Adafruit Neopixel) I would have preferred to use it as-is.

Regards - Philip

As I tried to explain, I can't declare it in global and then initialise it in setup() as declaration performs instantiation, which requires a parameter I need to determine dynamically.

Yes, you've said that. But, it is nonsense. It can be done AND that is the way to do it.

Quit beating around the bush. Define WHAT parameter needs to be determined at run-time and WHY a global instance with a begin() or init() method won't work, BY POSTING YOUR CODE!

pleriche:
I need to instantiate an object in setup() rather than in the global scope as I need to calculate the value of one of its properties. I was hoping I could just have a pointer to it in global scope which I would assign in setup().

But if I do that, it'll be destroyed when setup() exits - I'm warned that that might happen by the error "taking address of temporary" when I try to assign its address to the global pointer. But I need to use it in loop().

First suggestion (if you want to stick with the ridiculous setup/loop nonsense): Take a look at how LiquidCrystal accepts configuration data when it's instantiated.

Better suggestion: Use "int main (void)" for your code. Here's a "skeleton" for doing this:

int main (void)
{
    init (); // setup timers and interrupts

    // all your normal code goes here

    while (1); // main cannot exit (nowhere to exit TO)
}

...alternatively, if you want to run something in a loop, then do this in place of "[b]while (1);[/b]":

    while (1) {
        // this code loops forever
    }

Hope this helps.......