user42104: I have just started getting into Arduino and c++ programming!
For all the talk on the internet about c++ being incompatible with 8-bit and even 16-bit microcontrollers, how is it that Arduino Microcontrollers can safely handle c++ code, in terms of the ram usage? Is it that Arduino's library does not contain or utilize features such as constructors or objects (of C++) that (I believe) are very ram-usage-intensive?
Cheers!

user35469: To write effective code with limited resources (RAM, program space, processing), you need to know enough about the processor to avoid features which it can't do.  In this case you're limited on all three counts, so you want to get away from anything complex and slow.
A good start is to avoid any features later than C++98, or at least C++03.  These features generally come at a cost.
Beyond that, particular issues are:-

Polymorphism.  All classes using virtual members have a virtual method table, meaning every function call from that class needs to look up against a table.  On a small processor, this does slow down your function calls.  By all means use this where it's required, but if you have performance issues then you want your polymorphic classes to live at a higher level where the function calls happen less often.  Don't do this for low-level functions which get called thousands of times in a loop.
Exceptions.  Already covered by other answers.
Inline.  This is a good thing.  Where you can use this, it can claw back some processing cycles: not just from the function call itself; but also from further optimisation in the calling functions.

And of course general issues for embedded firmware on low-end micros:-

Dynamic memory allocation (new and delete, or most STL containers).  This is always an anti-pattern in embedded development.  It requires a chunk of RAM to be set aside for heap, and you always need to consider the possibility of allocation failing.  If you really need some kind of dynamic storage, consider whether a FIFO buffer or something better bounded would be appropriate.
Longer integers.
Integer multiply and divide.
Anything floating-point.
Anything using a lot of stack, whether this is lots of local variables, lots of function parameters, or over-enthusiastic function partitioning.


user13327: The talk about C++ being incompatible with small MCUs implies that developers would use features it provides. In a good C++ project you're expected to use vectors and iterators instead of C arrays, throw exceptions instead of returning error codes, use lambda-functions, templates etc.
As long as you don't use those features, C++ memory consumption is manageable. The reason for this is simple: such limited C++ is just a syntactic sugar around C structures and function pointers.
The problems usually start when you write a class which is complex enough that its constructor can fail. Then you have a tough choice to make: start using exceptions and drastically increase memory consumption, or write classes which pretend they never fail to construct (which often results in a program which pretends to work).

user42119: C++ is fine with Arduinos or other AVR based Systems.
I've been use it for quite a while in a home automation project.
The avr runtime does not support exceptions nor dynamic memory allocation, as has been stated. you can provide an implementation  though.
There is much of C++ left to make use of. here are some examples
Templates
They are very useful because, e.g. they allow to move work from runtime to compiletime. I use template for a replacement of the Arduino HAL functions DigitalWrite and others, without the runtime and code bloat. 
compare this 
int main(void)
{
        DDRB |= (1<<7);
        while(  (  ( PINB & (1<<6) ) !=(1<<6) ) )
                ;
        while(1)
        {
                _delay_ms(100);
                PORTB |= (1<<7);
                _delay_ms(100);
                PORTB &= ~(1<<7);
        }
}

to this
int main(void)
{
        IOPin<13> ledpin;
        IOPin<12> testpin;
        ledpin.SetDir(out);

        while(0 == testpin.State())
                ;
        while(1)
        {
                _delay_ms(100);
                ledpin.SetHigh();
                _delay_ms(100);
                ledpin.SetLow();
        }
}

The template based version is much more readable, and generates exactly the same assembler code. In the abovementioned linked article i explain the template and why this works.
more on templates
The following code uses the "curiously recurring template pattern" CRTP.
It is used to create a job class, which i use for a primitive scheduling 
This template builds a chain of registrable items. 
template<class registered>
struct Registered {
    static registered *registry;
    registered *chain;
    Registered() : chain(registry) {registry=static_cast<registered*>(this);}
};

The job class applies the CRTP pattern. The constructor takes the actual callback where the work is done, and how often the job is done.
class Job : public Registered<Job>
{
    voidFuncPtr m_p;
    uint16_t m_periodic;
    uint32_t m_lastrun;
    uint16_t m_initialdelay;
    public:
    Job(voidFuncPtr p,uint16_t periode=0,uint16_t initialdelay=0):m_p(p),m_periodic(periode),m_lastrun(0),m_initialdelay(initialdelay)
    {

    }
    void run(uint32_t t_ms)
    {
        // tbd handle wraparound !!
        if(t_ms >= m_lastrun + m_periodic + m_initialdelay)
        {
            m_p();
            m_lastrun=t_ms;
            m_initialdelay=0;
        }
    }
};

to use the job class i just create the instances for the jobs and pass lambdas or regular function pointers
Job jserial([](){mqttrouteradapter.handleSerialMQTT();},10);
Job jupdate(updatemc,1);
Job jprint(printstate,500);

initialize the beginning of the chain of jobs
template<> Job *Registered< Job >::registry = 0;

and inside main, run an infinite loop which calls the jobs.
while (1)
    {
        for ( auto p = Job::registry; p; p=p->chain )
        p->run(millis());
    }

Lambdas
Nice to avoid a callback function
instead of 
void handleserial(void)
{
    mqttrouteradapter.handleSerialMQTT();
}    
Job jserial(handleserial,10);

i can write something like
Job jserial([](){mqttrouteradapter.handleSerialMQTT();},10);

the new meaning of auto 
Allows to deduce the type automagically. This function iterates over "something" passed the second parameter. It compiles, if the passed type provides the operations/attributes used in the function.
And yes, this works only since c++17
void runRx(const char* data, auto msg_registry) {
    for (auto p = msg_registry; p; p = p->chain) {
        p->rx(data);
    }
}

using a recent compiler
If you want to use a recent compiler (The Arduino IDE uses gcc4.9) you can build your own gcc avr toolchain rather easily. Then you have gcc 7.2 with c++17 support !
An other very good reason to use gcc 7.2 is, that they have improved the error messages by a great deal.
My conclusion is, there is no excuse using c, except you havn't yet learned c++. And use a new compiler !

user10794: It's a misconception that using constructors or C++ in general requires lots of RAM. Plus, to be clear, the AVR processors like the Micro and Uno have separate RAM and PROGMEM (program memory). So, code for functions does not, in itself, use RAM.
As an example, this small program for the Micro:
int main ()
  {
  }

That uses only 206 bytes of PROGMEM and 0 bytes of RAM (according to the IDE).
Sketch uses 206 bytes (0%) of program storage space. Maximum is 28,672 bytes.
Global variables use 0 bytes (0%) of dynamic memory, leaving 2,560 bytes for local variables. Maximum is 2,560 bytes.


Adding in a class, with a constructor, and using that class, increases the memory a bit:
class foo
  {
  public:
  int bar;  // some class variable

  foo ()  // constructor
    {
    bar = 1;
    }
  };  // end of foo


foo nick;  // a global variable
int main ()
  {
  PORTD = nick.bar;
  }

That uses 2 bytes of RAM, and 278 bytes of PROGMEM. Hardly a lot.
Sketch uses 278 bytes (0%) of program storage space. Maximum is 28,672 bytes.
Global variables use 2 bytes (0%) of dynamic memory, leaving 2,558 bytes for local variables. Maximum is 2,560 bytes.


Of course, the more things you do, the more RAM and PROGMEM it takes, however the compiler generates quite efficient code, and the linker strips out things that are not needed by your code.


Is it that Arduino's library does not contain or utilize features such as constructors or objects (of C++) ...

A lot of libraries use classes and constructors (for example the Serial library, the Print class, and a lot of others). There is nothing inherently RAM-intensive about a constructor. It's just a function that does something, with an implied this pointer to the current instance of the class.


do lambdas work? (from a comment)

Yes you can use lambdas:
// array of function pointers
void (*doActionsArray []) () =
 {
 [] { Serial.println (0); } ,
 [] { Serial.println (1); } ,
 [] { Serial.println (2); } ,
 [] { Serial.println (3); } ,
 [] { Serial.println (4); } ,
 };

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  doActionsArray [3] ();
  }  // end of setup

void loop () { }



as long as you don't (extensively) use: the standard library, exceptions, templates ... (from a comment)

Templates can certainly simplify doing things like writing to, or reading from EEPROM and similar. For example:
#include <Arduino.h>  // for type definitions
#include <EEPROM.h>

template <typename T> unsigned int EEPROM_writeAnything (int ee, const T& value)
{
    const byte* p = (const byte*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
        EEPROM.write(ee++, *p++);
    return i;
}

template <typename T> unsigned int EEPROM_readAnything (int ee, T& value)
{
    byte* p = (byte*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}


The standard library? There are implementations for the Arduino. We have to bear in mind that RAM is limited, however if you are going to do something anyway that involves linked lists, etc. then the Standard Template Library will probably do what you want as efficiently as you could if you coded it "by hand".

The bottom line is you need to be aware of what you are coding on. I have seen examples like this:
float foo [1000];  // hold my readings

That blows the available RAM on a Uno straight away. Nothing to do with C++ per se.

The other thing to be aware of is some tricks you can usefully employ. One common one is to replace:
Serial.println ("Program starting.");

With:
Serial.println (F("Program starting."));

The first example causes the compiler to copy the string "Program starting." from PROGMEM into RAM, using some of your valuable RAM. The second example doesn't.

42104: <p>I have just started getting into Arduino and c++ programming!</p>

<p>For all the talk on the internet about c++ being incompatible with 8-bit and even 16-bit microcontrollers, how is it that Arduino Microcontrollers can safely handle c++ code, in terms of the ram usage? Is it that Arduino's library does not contain or utilize features such as constructors or objects (of C++) that (I believe) are very ram-usage-intensive?</p>

<p>Cheers!</p>
 35469: <p>To write effective code with limited resources (RAM, program space, processing), you need to know enough about the processor to avoid features which it can't do.  In this case you're limited on all three counts, so you want to get away from anything complex and slow.</p>

<p>A good start is to avoid any features later than C++98, or at least C++03.  These features generally come at a cost.</p>

<p>Beyond that, particular issues are:-</p>

<ul>
<li>Polymorphism.  All classes using virtual members have a <a href="https://en.wikipedia.org/wiki/Virtual_method_table" rel="nofollow noreferrer">virtual method table</a>, meaning every function call from that class needs to look up against a table.  On a small processor, this does slow down your function calls.  By all means use this where it's required, but if you have performance issues then you want your polymorphic classes to live at a higher level where the function calls happen less often.  Don't do this for low-level functions which get called thousands of times in a loop.</li>
<li>Exceptions.  Already covered by other answers.</li>
<li>Inline.  This is a <em>good</em> thing.  Where you can use this, it can claw back some processing cycles: not just from the function call itself; but also from further optimisation in the calling functions.</li>
</ul>

<p>And of course general issues for embedded firmware on low-end micros:-</p>

<ul>
<li>Dynamic memory allocation (new and delete, or most STL containers).  This is <strong><em>always</em></strong> an <a href="https://en.wikipedia.org/wiki/Anti-pattern" rel="nofollow noreferrer">anti-pattern</a> in embedded development.  It requires a chunk of RAM to be set aside for heap, and you always need to consider the possibility of allocation failing.  If you really need some kind of dynamic storage, consider whether a FIFO buffer or something better bounded would be appropriate.</li>
<li>Longer integers.</li>
<li>Integer multiply and divide.</li>
<li>Anything floating-point.</li>
<li>Anything using a lot of stack, whether this is lots of local variables, lots of function parameters, or over-enthusiastic function partitioning.</li>
</ul>
 13327: <p>The talk about C++ being incompatible with small MCUs implies that developers would use features it provides. In a <em>good</em> C++ project you're expected to use vectors and iterators instead of C arrays, throw exceptions instead of returning error codes, use lambda-functions, templates etc.</p>

<p>As long as you don't use those features, C++ memory consumption is manageable. The reason for this is simple: such limited C++ is just a syntactic sugar around C structures and function pointers.</p>

<p>The problems usually start when you write a class which is complex enough that its constructor can fail. Then you have a tough choice to make: start using exceptions and drastically increase memory consumption, or write classes which <em>pretend</em> they never fail to construct (which often results in a program which <em>pretends</em> to work).</p>
 42119: <p>C++ is fine with Arduinos or other AVR based Systems.
I've been use it for quite a while in a home automation project.</p>

<p>The avr runtime does not support exceptions nor dynamic memory allocation, as has been stated. <a href="http://www.avrfreaks.net/forum/c-new-delete-operator-confusion" rel="nofollow noreferrer">you can provide an implementation  though</a>.</p>

<p>There is much of C++ left to make use of. here are some examples</p>

<p><strong>Templates</strong></p>

<p>They are very useful because, e.g. they allow to move work from runtime to compiletime. I use template for a <a href="https://haarer.github.io/c++/avr/templates/i/o/2018/01/21/c++-template-based-hardware-access-vs-classic-approach.html" rel="nofollow noreferrer">replacement of the Arduino HAL functions DigitalWrite and others, without the runtime and code bloat</a>. </p>

<p>compare this </p>

<pre><code>int main(void)
{
        DDRB |= (1&lt;&lt;7);
        while(  (  ( PINB &amp; (1&lt;&lt;6) ) !=(1&lt;&lt;6) ) )
                ;
        while(1)
        {
                _delay_ms(100);
                PORTB |= (1&lt;&lt;7);
                _delay_ms(100);
                PORTB &amp;= ~(1&lt;&lt;7);
        }
}
</code></pre>

<p>to this</p>

<pre><code>int main(void)
{
        IOPin&lt;13&gt; ledpin;
        IOPin&lt;12&gt; testpin;
        ledpin.SetDir(out);

        while(0 == testpin.State())
                ;
        while(1)
        {
                _delay_ms(100);
                ledpin.SetHigh();
                _delay_ms(100);
                ledpin.SetLow();
        }
}
</code></pre>

<p>The template based version is much more readable, and generates exactly the same assembler code. In the abovementioned linked article i explain the template and why this works.</p>

<p><strong>more on templates</strong></p>

<p>The following code uses the "curiously recurring template pattern" CRTP.
It is used to create a job class, which i use for a primitive scheduling </p>

<p>This template builds a chain of registrable items. </p>

<pre><code>template&lt;class registered&gt;
struct Registered {
    static registered *registry;
    registered *chain;
    Registered() : chain(registry) {registry=static_cast&lt;registered*&gt;(this);}
};
</code></pre>

<p>The job class applies the CRTP pattern. The constructor takes the actual callback where the work is done, and how often the job is done.</p>

<pre><code>class Job : public Registered&lt;Job&gt;
{
    voidFuncPtr m_p;
    uint16_t m_periodic;
    uint32_t m_lastrun;
    uint16_t m_initialdelay;
    public:
    Job(voidFuncPtr p,uint16_t periode=0,uint16_t initialdelay=0):m_p(p),m_periodic(periode),m_lastrun(0),m_initialdelay(initialdelay)
    {

    }
    void run(uint32_t t_ms)
    {
        // tbd handle wraparound !!
        if(t_ms &gt;= m_lastrun + m_periodic + m_initialdelay)
        {
            m_p();
            m_lastrun=t_ms;
            m_initialdelay=0;
        }
    }
};
</code></pre>

<p>to use the job class i just create the instances for the jobs and pass lambdas or regular function pointers</p>

<pre><code>Job jserial([](){mqttrouteradapter.handleSerialMQTT();},10);
Job jupdate(updatemc,1);
Job jprint(printstate,500);
</code></pre>

<p>initialize the beginning of the chain of jobs</p>

<pre><code>template&lt;&gt; Job *Registered&lt; Job &gt;::registry = 0;
</code></pre>

<p>and inside main, run an infinite loop which calls the jobs.</p>

<pre><code>while (1)
    {
        for ( auto p = Job::registry; p; p=p-&gt;chain )
        p-&gt;run(millis());
    }
</code></pre>

<p><strong>Lambdas</strong></p>

<p>Nice to avoid a callback function</p>

<p>instead of </p>

<pre><code>void handleserial(void)
{
    mqttrouteradapter.handleSerialMQTT();
}    
Job jserial(handleserial,10);
</code></pre>

<p>i can write something like</p>

<pre><code>Job jserial([](){mqttrouteradapter.handleSerialMQTT();},10);
</code></pre>

<p><strong>the new meaning of auto</strong> </p>

<p>Allows to deduce the type automagically. This function iterates over "something" passed the second parameter. It compiles, if the passed type provides the operations/attributes used in the function.
<a href="http://en.cppreference.com/w/cpp/language/auto" rel="nofollow noreferrer">And yes, <strong>this</strong> works only since c++17</a></p>

<pre><code>void runRx(const char* data, auto msg_registry) {
    for (auto p = msg_registry; p; p = p-&gt;chain) {
        p-&gt;rx(data);
    }
}
</code></pre>

<p><strong>using a recent compiler</strong></p>

<p>If you want to use a recent compiler (The Arduino IDE uses gcc4.9) you can <a href="https://github.com/haarer/toolchain68k" rel="nofollow noreferrer">build your own gcc avr toolchain rather easily</a>. Then you have gcc 7.2 with c++17 support !
An other very good reason to use gcc 7.2 is, that they have improved the error messages by a great deal.</p>

<p>My conclusion is, there is no excuse using c, except you havn't yet learned c++. And use a new compiler !</p>
 10794: <p>It's a misconception that using constructors or C++ in general requires lots of RAM. Plus, to be clear, the AVR processors like the Micro and Uno have separate RAM and PROGMEM (program memory). So, code for functions does not, in itself, use RAM.</p>

<p>As an example, this small program for the Micro:</p>

<pre class="lang-c++ prettyprint-override"><code>int main ()
  {
  }
</code></pre>

<p>That uses only 206 bytes of PROGMEM and 0 bytes of RAM (according to the IDE).</p>

<pre class="lang-none prettyprint-override"><code>Sketch uses 206 bytes (0%) of program storage space. Maximum is 28,672 bytes.
Global variables use 0 bytes (0%) of dynamic memory, leaving 2,560 bytes for local variables. Maximum is 2,560 bytes.
</code></pre>

<hr>

<p>Adding in a class, with a constructor, and using that class, increases the memory a bit:</p>

<pre class="lang-c++ prettyprint-override"><code>class foo
  {
  public:
  int bar;  // some class variable

  foo ()  // constructor
    {
    bar = 1;
    }
  };  // end of foo


foo nick;  // a global variable
int main ()
  {
  PORTD = nick.bar;
  }
</code></pre>

<p>That uses 2 bytes of RAM, and 278 bytes of PROGMEM. Hardly a lot.</p>

<pre class="lang-none prettyprint-override"><code>Sketch uses 278 bytes (0%) of program storage space. Maximum is 28,672 bytes.
Global variables use 2 bytes (0%) of dynamic memory, leaving 2,558 bytes for local variables. Maximum is 2,560 bytes.
</code></pre>

<hr>

<p>Of course, the more things you do, the more RAM and PROGMEM it takes, however the compiler generates quite efficient code, and the linker strips out things that are not needed by your code.</p>

<hr>

<blockquote>
  <p>Is it that Arduino's library does not contain or utilize features such as constructors or objects (of C++) ...</p>
</blockquote>

<p>A lot of libraries use classes and constructors (for example the Serial library, the Print class, and a lot of others). There is nothing inherently RAM-intensive about a constructor. It's just a function that does something, with an implied <strong>this</strong> pointer to the current instance of the class.</p>

<hr>

<blockquote>
  <p>do lambdas work? (from a comment)</p>
</blockquote>

<p>Yes you can use lambdas:</p>

<pre><code>// array of function pointers
void (*doActionsArray []) () =
 {
 [] { Serial.println (0); } ,
 [] { Serial.println (1); } ,
 [] { Serial.println (2); } ,
 [] { Serial.println (3); } ,
 [] { Serial.println (4); } ,
 };

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  doActionsArray [3] ();
  }  // end of setup

void loop () { }
</code></pre>

<hr>

<blockquote>
  <p>as long as you don't (extensively) use: the standard library, exceptions, templates ... (from a comment)</p>
</blockquote>

<p>Templates can certainly simplify doing things like writing to, or reading from EEPROM and similar. For example:</p>

<pre><code>#include &lt;Arduino.h&gt;  // for type definitions
#include &lt;EEPROM.h&gt;

template &lt;typename T&gt; unsigned int EEPROM_writeAnything (int ee, const T&amp; value)
{
    const byte* p = (const byte*)&amp;value;
    unsigned int i;
    for (i = 0; i &lt; sizeof(value); i++)
        EEPROM.write(ee++, *p++);
    return i;
}

template &lt;typename T&gt; unsigned int EEPROM_readAnything (int ee, T&amp; value)
{
    byte* p = (byte*)&amp;value;
    unsigned int i;
    for (i = 0; i &lt; sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}
</code></pre>

<hr>

<p>The standard library? There are implementations for the Arduino. We have to bear in mind that RAM is limited, however if you are going to do something <em>anyway</em> that involves linked lists, etc. then the Standard Template Library will probably do what you want as efficiently as you could if you coded it "by hand".</p>

<hr>

<p>The bottom line is you need to be aware of what you are coding on. I have seen examples like this:</p>

<pre><code>float foo [1000];  // hold my readings
</code></pre>

<p>That blows the available RAM on a Uno straight away. Nothing to do with C++ per se.</p>

<hr>

<p>The other thing to be aware of is some tricks you can usefully employ. One common one is to replace:</p>

<pre><code>Serial.println ("Program starting.");
</code></pre>

<p>With:</p>

<pre><code>Serial.println (F("Program starting."));
</code></pre>

<p>The first example causes the compiler to copy the string "Program starting." from PROGMEM into RAM, using some of your valuable RAM. The second example doesn't.</p>
