If statement and memory allocation

Hi everyone,
I have a question, at the end of an if statement, all local variables between {} should be de-allocated.
This is the following code I'm Running :

#include <Motor.h>
#include <stdlib.h>


#include <Arduino.h>
#include <SoftwareSerial.h>
#include <MemoryFree.h>


bool push = 0;
bool incchar = 0;

void setup() {
  Serial.begin(9600);


  /*
  */
  if (push ==1){
    Motor m1(SERVOS,RIGHT,0,0,"m1");
    Motor m2(SERVOS,RIGHT,40,4400,"m2");
  }
  
  Serial.begin(9600);
  Serial.println(getFreeMemory());

}

void loop() {

  delay(100000);

}

The code of the Motor Class
Motor.h :

#ifndef __MOTOR__H__
#define __MOTOR__H__
#include <Arduino.h>


typedef enum{LEFT,RIGHT} Direct_t;
typedef enum{STEPPERS, SERVOS} Moteur_t;

class Motor{
    private :
        Direct_t direction;
        Moteur_t type;
		int speed;
        float angle;
        char nameBuff[3];
        char* name;

    public :
		Motor(Moteur_t type = STEPPERS, Direct_t direction = LEFT, int speed = 0, float angle = 0,char* name = "");
		~Motor();

		//setters & getters
        int getSpeed();
        void setSpeed(int);
        Direct_t getDir();
        void setDir(Direct_t);
        float getAngle();
        void setAngle(float);
        void tourner(int ID, Direct_t side, int speed);
        char* getName();
        void setName(char*);
        Moteur_t getType();
        void setType(Moteur_t);

        //tourner
        void tourner(String, String, double, int, int*, String*, int);
        static double positions(double);
};

#endif

Motor.cpp :

#include "Motor.h"
#include <Arduino.h>
#include "DynamixelSerial.h"


//constructeur qui permet de construire des objets avec 0, 1, 2, 3 ou 4 arguments selon les besoins.
Motor::Motor(Moteur_t type, Direct_t direction, int speed, float angle, char* name) : type{ type }, direction{ direction }, speed{ speed }, angle{angle}
{
  strcpy(this->nameBuff,name);
  this->nameBuff[strlen(name)] = '\0';
  this->name = this->nameBuff;
}

Motor::~Motor() {
	//vide car pas de variables d'instances dynamiques
  //Serial.println(F("Motor deleted"));
}

int Motor::getSpeed() {
    return speed;
}

void Motor::setSpeed(int s) {
    speed = s;
}

Direct_t Motor::getDir() {
    return direction;
}

void Motor::setDir(Direct_t dir) {
    direction = dir;
}

float Motor::getAngle() {
    return angle;
}

void Motor::setAngle(float angle) {
    this->angle = angle;
}

void Motor::tourner(int ID, Direct_t side, int speed){

}

void Motor::setName(char* name){
  strcpy(this->nameBuff,name);
  this->nameBuff[strlen(name)] = '\0';
  this->name = this->nameBuff;
}

char* Motor::getName(){
    return this->name;
}
void Motor::setType(Moteur_t type){
    this->type = type;
}
Moteur_t Motor::getType(){
    return this->type;
}

void Motor::tourner(String names, String directions, double angle, int vitesse, int* tab_ID, String* tab_names, int oldPositions){
   int newPositions;
   int ID;
   for (int i=0; i<5; i++){
      if (names == tab_names[i])
        ID = tab_ID[i];
        if (directions == "LEFT")
          newPositions = oldPositions - positions(angle);
        else
          newPositions = oldPositions + positions(angle);
        oldPositions = newPositions;
        Dynamixel.moveSpeed(ID, newPositions, vitesse);
   }
}

double Motor::positions(double angle){
    return (angle * 3.41);
}

So logically, I should have the same thing returned from getFreeMemory() with or without the if statement.
But with the if statement I have a free memory of 1560 like when I declare m1 and m2, and without I have 1604. If you have any idea of where I am wrong I'll be very thankful :slight_smile:
Thanks for reading ! Have a good day !
Syndorik

Are you asking how the compiler optimises code?

Not really, I just want to know why my memory is not freed when I reach the end of the if statement !

I believe that any local variables (e.g. those inside the if statement) are using the stack, not the heap, which is probably what the FreeMemory module is calculating. The compiler needs to allocate space for m1 and m2 regardless of them being called or not.

Interesting, so actually, if m1 and m2 are not called, getMemoryFree() will considered them as called, but I still have my free space on my SRAM ?

Look at your code. You measure free memory in ONE place. That happens AFTER you allocated and deallocated memory for the Motor instances.

I can't imagine what you think one data point is going to tell you.

The compiler can see that the value in push will never change, so it doesn't even output code to create the instances of the Motor class. You could have determined that that is the case by looking at the intermediate files produced during the build process.

Just what do you think the problem is? Other than you not understanding what is happening, that is.

OKay but then could you explain me why I get two different number for my memory allocation ? I mean when I don't put the if statement I have 1604 of free memory and when I put it I have 1560 of free Memory. So even if I'm wrong in the way I'm using the method getFreeMemory there's still something weird. And I think what blh64 said was maybe the reason of this weirdness.

And for the record I did this on purpose, the if statement that will never be true. It was to see where my memory was going.
So maybe I don't know what's going on, but I'm here to understand that, so please don't be that rude.

The stack grows from one end of SRAM. The heap grows from the other end. When the meet, the fecal matter contacts the rotating vanes.

What getFreeMemory SHOULD be doing is determine how much memory is available between the stack and the heap. What it ACTUALLY does will remain a mystery until you post a link to the library that contains that method.

Are you saying that

This...

 if (push ==1){
    Motor m1(SERVOS,RIGHT,0,0,"m1");
    Motor m2(SERVOS,RIGHT,40,4400,"m2");
  }
  Serial.println(getFreeMemory());

shows less free memory to this...

  {
    Motor m1(SERVOS,RIGHT,0,0,"m1");
    Motor m2(SERVOS,RIGHT,40,4400,"m2");
  }
  Serial.println(getFreeMemory());

Those two seem equivalent to me, in terms of stack usage within a function. Declaring the Motor objects should not be optimised away by the compiler as the constructor may do things like set output pins, even if the Motor object is never used. The first version won't call the constructor, but the memory for the object itself will be allocated on the stack.

Syndorik:
OKay but then could you explain me why I get two different number for my memory allocation ? I mean when I don't put the if statement I have 1604 of free memory and when I put it I have 1560 of free Memory.

Some / all of the difference are the string constants.

  this->nameBuff[strlen(name)] = '\0';

...and its ilk are not necessary. Get rid of them.

I think most compilers will not actually free the memory of "local variables" from their stack until the function exits, because the stack frame is typically set up at the function entry, and not destroyed until the end.
So if you have:

void foo() {
   uint8_t foo[10];
   if (Serial.available() > 0) {
        uint8_t buffer[100];
          :  // blah blah - process serial data
   }
   // show how much mem is between top of heap and bottom of stack
   Serial.print(MagicFreeMemoryCheck());
}

then probably the function will allocate a stack frame of 110 bytes at the entry of foo, and delete it at the return, but the free memory check will show 110 bytes missing, even though "buffer" is out of scope.

If you're lucky, the compiler will be smart enough to reuse some of that memory if appropriate:

void foo() {
   uint8_t foo[10];
   if (Serial.available() > 0) {
        uint8_t buffer[100];
          :  // blah blah - process serial data
   }
   if (Serial1.available() > 0) {
        uint8_t anotherBuf[100];
          :  // blah blah - process serial1 data
   }
   // show how much mem is between top of heap and bottom of stack
   Serial.print(MagicFreeMemoryCheck());
}

Should show the same 110 bytes used.

At least, that how the C compilers I'm used to would work. It's somewhat possible that C++ has stricter rules...

If you need to know for sure, look at the assembly code generated.

westfw:
I think most compilers will not actually free the memory of "local variables" from their stack until the function exits...

I know the constructor / destructor have to be called within the enclosing scope. (Inside the "if (push ==1)" then-clause.)

Looking at the disassembly of a simple example it appears link-time-optimization causes the stack to be adjusted at the start of main and flattens the entire code into a single function.

I have a question, at the end of an if statement, all local variables between {} should be de-allocated.

Your confusing scope and memory allocation. Bark up your claim with a reference to the ansi spec!

Mark

MorganS:
Those two seem equivalent to me, in terms of stack usage within a function. Declaring the Motor objects should not be optimised away by the compiler as the constructor may do things like set output pins, even if the Motor object is never used. The first version won't call the constructor, but the memory for the object itself will be allocated on the stack.

Don't assume this. I've managed to contrive code where EEPROM read functions get completely removed by the optimizer, and those function definitely mess with volatile variables.

It's pointless to fret about exactly how the compiler optimizes certain things, because it is allowed a wide amount of discretion to do what it wants. It may do one thing now, and change completely in the next update. Or it'll change when you modify an unrelated, distant part of your code.