C++ for Arduino: any tips?

After using plain C for some 20 years, I am finally getting around to learning C++. Apparently it is generally considered that C++ is not ideal for micro-controller programming. However a number of Arduino libraries are written in C++. And writing a few little test routines, I was pleased to see that compiled binaries from Object-Oriented code were barely larger than their non-OO equivalents. Including Mikal Hart’s <Streaming.h> library actually made some sketches shrink.

So I thought I’d just ask here if anybody has any thoughts, tips, or pointers regarding C++ on the Arduino?

PS. If anybody else is thinking of moving from C to C++, but has been put-off (as I was) by poor explanations in huge multi-volume textbooks, I can recommend Gregory Satir & Doug Brown’s book, published by O’Riley.

Apparently you are not supposed to use constructors to do stuff for static global objects, so don't. Have a ".initialize" or ".begin" function that becomes the constructor. I'm not sure if this applies for dynamically created objects.

Also you can't use exceptions in Arduino

Oh and the IDE is supposed to magically (RegEx) find functions and write function prototypes for you. It will try to insert them after all the includes or preprocessor directives but before any statements. There are many ways for this to fail.

The IDE also stitches all your .PDE files into one gigantic .CPP file before compiling, keep that in mind. I'm not sure about the order in which the files are stitched together.

This is coming from somebody who made an Arduino IDE clone, there's so much background pre-processing done to your code. There's a lot of RegEx stuff dedicated to stripping out your comments, looking for #include directives, and transforming function declarations into prototypes.

C++ for the Arduino isn't really a problem, as long as you keep your memory footprint low. So don't go overboard with copy constructors, virtual functions, dynamic objects etc.

In the end, the C++ veneer on the Arduino is mostly a way to organise library functions in classes, comments with // and to able to write: for (int i=0; ...

Korman

Korman - do you have a sense of how expensive a virtual function is? I was planning on using one for the first time & was wondering if I should be hesitant. In my case it is pretty simple: I have an abstract class A and two derived classes B and C, each of which has a different implementation of the function.

One isn't a problem, it's just a pointer in the data to allow overloading. It's getting expensive if you have dozens of them.

Korman

Thanks guys. I think I can manage without static globals, though exception handling could have been useful. The comments on the build process were interesting and prompted me to look a little further into it. If anybody is using a Makefile instead of the IDE, I'd be interested to hear their comments.

Interesting. What's the problem with constructors for static globals? I've been doing this plenty, haven't run into any non obvious problem with it.

For makefile, search the forum. I got mine from a forum thread.

maniacbug:
Interesting. What’s the problem with constructors for static globals? I’ve been doing this plenty, haven’t run into any non obvious problem with it.

For makefile, search the forum. I got mine from a forum thread.

There isn’t any real problems, but there are extreme cases where you should avoid them

For example, “Serial”, if you used the constructor for initializing the UART module, but the user decided to never use it, then you’ve occupied those pins and FIFO memory without the user knowing so.

Or since the constructors are called before main(), imagine if your watchdog timer is enabled, if your constructors takes too long to execute, then you risk never having your code launch

The C / C++ debate is not unique to microcontrollers. The biggest complaint I hear about C++ from my C friends is that all the pointer dereferencing is expensive from a performance standpoint. There are definitely things inside C++ where stuff is done for you, and resources consumed you didn't expect to be consumed, if you don't know how features are implemented.

All that said, I am having great luck with C++ on the Arduino. I was impressed that it supports templates and some other language features. You'll find out that new and delete and new[] and delete[] are not implemented, but that's easy to fix. Be careful though, I noticed that the memory allocator uses a lot of RAM. Wherever I can, I just allocate objects on the stack instead of dynamically allocating them.

Works for me!

Oh, one iother thing. If you do use dynamic memory allocation and you have a leak, you're probably going to figure it our very quickly! :P

What's the problem with constructors for static globals? ... There isn't any real problems

Global / static constructors are called before init. Which means the core has not yet been initialized. I'd call that a "real problem".

Follow the advice given earlier. Do as little as possible in constructors.

frank26080115:
Apparently you are not supposed to use constructors to do stuff for static global objects, so don’t. Have a “.initialize” or “.begin” function that becomes the constructor. I’m not sure if this applies for dynamically created objects.

There are some subtle problems with static global objects, in particular the time when the constructors are called. Here is an interesting page:

I should point out that objects will have their constructors called (therefore you are using them) even if they do nothing (the default constructor). But if they do something important then the initialization order may bite you.

I don’t think there will be a problem with dynamic objects because one presumes the constructor is called when the object is instantiated (when else, eh?).

You’ll find out that new and delete and new and delete are not implemented …

True, but you can implement them yourself, as I showed here (look for “operator new”):

Wherever I can, I just allocate objects on the stack instead of dynamically allocating them.

I think that is very sensible. Saves creating possible heap fragmentation.

Global / static constructors are called before init. Which means the core has not yet been initialized.

That’s another potential problem too of course.

I think doing something like zeroing a variable is OK in a constructor. Relying on other objects or libraries is problematic.

[quote author=Nick Gammon link=topic=57858.msg416822#msg416822 date=1302329373]

skyjumper: Wherever I can, I just allocate objects on the stack instead of dynamically allocating them.

I think that is very sensible. Saves creating possible heap fragmentation. [/quote]

Definitely use KISS with C++ - for example, if you have a class that has a field of another class type in it, then when you create an instance of the first, the second class goes in the same place the first went - heap or stack. Which is fine, if you keep tight reign on your object model. But naturally, it'll become harder to track memory usage as you start using more complex object models.

The memory structure on the Arduino isn't protected like on a PC, so when the stack fills up and starts overwriting your heap, you might not notice immediately, but your data will :)

Also, I had to throw in a pure virtual call handler - for when you have a base class pointer that has a pure virtual member function, and it's missing from the object's vtable (because of bad pointer casting, usually). Here are the four functions I added to be able to do C++ work:

// abstract base class 'just in case' handler.
extern "C" { void __cxa_pure_virtual() {} void __cxa_guard_acquire() {} void __cxa_guard_release() {} };

// FreeRTOS/C++ integration - trivial version.
void* operator new(unsigned int size) 
{
  return pvPortMalloc(size);
}

Caveat: I'm not recommending trying to use FreeRTOS, or this memory operator. Just an example.

HTH