Hi, I have a monitoring Class and when a condition is matched an alarm is called inside it. The alarm function has variables that should be kept for a while, like some time from millis(), and the program should be running without stopping in it, but after some time I dont need these variables from the Alarm function and need to free the memory. What's the best way to do it ?
read about calloc(), malloc(), and free().
Please, do NOT use malloc() et al. That is the stone age way of doing things, and is risky if not done exactly right. Define one or more object classes to contain the information. When you need it, use new to create an instance of the needed class(es). When you're done with it, use delete to discard the instance(s). That is the RIGHT way to do it.
In the C languages, read about SCOPE.
Elements, variables, classes etc are only needed when they’re needed.
If you manage your items properly, they only use memory when it’s relevant.
Thanks, that's new for me.
The code will be something like this ? :
#include <iostream>
using namespace std;
class answerAlarm{
public:
void myAction ()
{
cout << "Wake up" << endl;
}
bool isDone = false;
};
class alarm{
public:
void alarmOn ()
{
if (ans1 == NULL)
{
cout << "Creating" << endl;
ans1 = new answerAlarm ();
cout << "Created" << endl;
}
ans1->myAction ();
cout << "Action" << endl;
if (ans1->isDone)
{
cout << "Delete" << endl;
delete ans1;
ans1 = NULL;
if (ans1 == NULL)
{
cout << "Pointer deleted and NULL" << endl;
}
}
}
answerAlarm *ans1 = NULL;
};
int main (){
alarm al1;
//Alarm activated
al1.alarmOn (); //First attempt
al1.alarmOn (); //Second attempt
//Alarm deactivated
al1.ans1->isDone = true;
al1.alarmOn ();
return 0;
}
It's in c++ just to know the concept, in Arduino it will be the same, alright ?
The constructor should create an object. Usually you will not need new. Also you should not need a pointer.
When the object leaves the scope where it was created, the destructor will be called automatically. So no delete needed either.
Plenty examples/tutorials available on the web.
I.e.
Learncpp.com
I am not sure if this effort will bring you much if you only want to free some memory. As suggested, scope or functions can also do that for you and you will need to master that before you start with classes.
You are ignoring several very important things. First, that he wants to create some variables, and discard them at times that are known only at run-time. He has no choice but to use new and delete to accomplish that. Next, the constructor does NOT create the object. new creates the object, and only then is the constructor called to initialize the newly created object. It is new that actually allocates the memory needed by the object, and causes the objects constructor to be called.
...is problematic.
Maybe I should have been more clear. I meant instantiating an instance of an object of the user made class. Like this:
MyClass instance_of_my_class();
This will cause the constructor, that will make space available. When the scope is left, the instance will be automatically deleted. But this will not bring more than a struct could also do.
I think pointers should only be used to hand large chunks of memory to functions (like char arrays) or with special things such as linked lists.
Pointers take another bit of memory, so the amount of memory is likely to increase with use of pointers. With use of classes as well...
That is why I agree with lastchancename that looking at scope and using functions may be far more efficient. As soon as the function is left, the memory used by the function will also be released for other uses.
In this specific case, the alarm time may be set in a static variable. That will keep existing during the full program. That should take 4 bytes or so... Not really much. If you want a flexible amount of alarms, you could put the alarm times in a std::list<>. But why not reserve space for max 10 alarms (40 bytes)? Would you ever need more than that?
My point is that pointers are not easy. It is quite easy to cause a memory leak. And that is far worse than just reserve a few bytes beforehand. Because you will then know what you are doing. With memory leak you will never get the memory back (unless you do a reset) and one day your program will crash in a very unpredictable way.
I shoud have been more clear too. I just need the alarm variables while it's been activated, I mean the Monitoring Class will call the Alarm class after a condition, the Alarm Class will inform the user (Telegram Bot) and wait some time for an answer, if the user didn't answer after it, the program will set the configuration by itself, disable the alarm and continue running.
I think the code will be something like this, except that I will check for a specific user answer to validate it. Do you have another way or will change anything on it ?
#include <Arduino.h>
char userAnswer=' ';
class answerAlarm{
public:
bool myAlarmAction (){
if((attempts < 3)&&(userAnswer==' ')){
if(millis()-userDelay >= 10000){
Serial.println("Problem found! \n Alarm is activated !\n Select an option...");
Serial.println("Attempt: " + String(attempts)+"/2");
attempts++;
userDelay = millis();
}
}else{
Serial.println("Attempt limit reached or User answered. ");
return false;
}
return true;
}
private:
byte attempts = 0;
unsigned long userDelay = 0;
};
class alarm{
public:
void alarmOn(){
if (ans1 == NULL){
ans1 = new answerAlarm ();
}
if(!(ans1->myAlarmAction())){
Serial.println("Pointer deleted and set to NULL");
delete ans1;
ans1 = NULL;
}
}
private:
answerAlarm *ans1 = NULL;
};
void setup()
{
Serial.begin(9600);
}
void loop()
{
static alarm al1;
//Simulating user input
while(Serial.available()>0){
userAnswer = Serial.read();
}
al1.alarmOn();
if(userAnswer != ' ') userAnswer = ' ';
}
Is your goal to conserve memory?
To be honest, I do not see how classes or pointers will help you to reduce memory.
The F macro may help to reduce ram memory usage by keeping text in rom.
Normal functions will only use ram if called. So there seems to be no need for classes.
Classes may help to group data and functions that are related. I would expect that an alarm class has the following attributes:
alarmEnabled
alarmTriggered
And the following functions:
alarmAction()
resetAlarm()
alarmHandling()
You have alarmOn and to me it is not clear what that is supposed to do (enable or trigger)
Also class names (by convention) should start with a capital.
It seems one alarm class instead of two might be easier here...
Yes, it's in ESP8266 and I'm already have many libraries loaded just to start, WifiManager, UniversalTelegramBot, NTP, SPIFF, and I'm going to have 4 objects to be monitored continuously through the level from 4 independent pins.
I just want to keep in RAM what I'm really need.
Ok, I just updated the names to be more clear. Anything else ?
#include <Arduino.h>
char userAnswer=' ';
//Class created just to store temporary the variables while the alarm is active.
class AlarmActive{
public:
bool action(){
if((attempts < 3)&&(userAnswer==' ')){
if(millis()-userDelay >= 10000){
Serial.println("Attempt: " + String(attempts));
attempts++;
userDelay = millis();
}
}else{
Serial.println("Attempt limit reached or User answered !");
return false;
}
return true;
}
private:
byte attempts = 0;
unsigned long userDelay = 0;
};
class Monitor{
public:
void alarmTrigger(){
//Some condition to enable the Alarm
if(userAnswer=='a'){
if (alarm1 == NULL){
alarm1 = new AlarmActive();
}
if(!(alarm1->action())){
Serial.println("Pointer deleted and set to NULL");
delete alarm1;
alarm1 = NULL;
}
}
}
private:
AlarmActive *alarm1 = NULL;
};
void setup()
{
Serial.begin(9600);
}
void loop()
{
static Monitor m1;
//Simulating user input
while(Serial.available()>0){
userAnswer = Serial.read();
}
m1.alarmTrigger();
if(userAnswer != ' ') userAnswer = ' ';
}
Eight bytes are need to store the answerAlarm
data plus a four byte pointer plus at least eight bytes for the heap header. Your code needs at least 20 bytes of storage to store 8 bytes of data.
This is a good time to mention that premature optimization is the root of all evil. This is a good practical read on the subject.
I see. I will finish the project and look for this optimization later, but the topic was to know which method is better to do that, and the New and Delete seems to be more appropriate.
I am not at all convinced.
It is very easy to mess up your memory using pointers. Also, if you forget to delete your variable, you will use more and more memory. It is much easier to reserve some memory beforehand and reuse it again and again....
How to do that and when do you use New and Delete ?
Generally you use pointers to drag around large chunks of memory from one place to another (from loop to a function or back). Arrays are pointers, so you use the more often than you might realise. Printing of C-strings also uses pointers under the hood. Also searching of characters in a string will return you a pointer to the position where the character was found.
New and delete are used to reserve memory in run time. So if you cannot foresee that you will need that bit of memory at compile time. You can use this to make linked lists, circular lists, stacks, etc. For example inserting a value in a list can be done using pointers. If you would use an array, you would need to copy all values after the point of insertion one place up. Then you can insert your new value. I am presuming here that you reserved a larger array than needed beforehand, otherwise you will need to initialise a second (larger) array and copy all values.... So, here pointers give you flexibility and speed. But it will (generally) not save memory. All the pointers need to be stored as well. This will take more memory than an array that is much larger than needed.
You can also do these things with std::list and std::vec. Those are implemented using pointers, but you as a user do not need to know that... You can simply insert new elements at a certain position and the std::list will take care of all the pointers. With pointers you can also make (binary) trees.
You can reserver space by just making a global variable:
int myChunk[100];
will reserve a place where you can store 100 integers.
This is more safe than using pointers, as the compiler will take into account this amount of memory and will warn you when you reserve more memory than present in your controller...
If you take more and more memory via new, you will get very weird results when the stack hits the heap (when your stack memory plus your heap memory are larger than the memory of the controller). This may take hours, days or years to happen. Or it may never happen. But once it happens it will cause a crash and it will be very difficult to trace why the crash happened (power failure might be your first thought).
The thing is: a pointer to some data will always use more memory than that data, so, just use the data... Just now I got this and the use of new and delete when using memory.
New and Delete are not to save memory, they are to reserve memory for some unknown data for a while.