Go Down

Topic: The HATRED for String objects - "To String, or not to String" (Read 13 times) previous topic - next topic

GoForSmoke


For most cases this will result in no pointer change at all and a simple adjustment of the allocated length - usually out into free space in most use-cases on a small system like this.


Assuming the String is at the top of the heap in 'most cases'. Otherwise not.

Andy Brown, I think you will find that Nick knows more about the code than you credit. And he isn't given to make unfounded claims.

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

zoomkat

So is there anything in the external programming that can be done to free the no longer used allocated memory space?
Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   8)

retrolefty


So is there anything in the external programming that can be done to free the no longer used allocated memory space?


Perhaps enable the WDT, let if time out, and have the sketch start all over?  :D

zoomkat

Quote
Perhaps enable the WDT, let if time out, and have the sketch start all over? 


Close to what my magic 8-Ball suggested.  :)
Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   8)

Nick Gammon


Andy Brown, I think you will find that Nick knows more about the code than you credit. And he isn't given to make unfounded claims.


I don't have any argument with Andy. I think he has the fixed malloc/free library on his site anyway.

There is a bug in 'free' in the current Arduino library. I think we are all agreed on that. What Andy says about free spaces being combined by the library would almost certainly be correct. But the bug in question is something to do with the first (or last?) allocated block not being freed correctly, or something like that.

I have heard people say that, with the fixed free() installed, they can use String objects at some length with no problems, which supports what Andy says about the library combining unused blocks.
http://www.gammon.com.au/electronics

Nick Gammon


So is there anything in the external programming that can be done to free the no longer used allocated memory space?


In one of the threads about this problem I suggested incorporating the corrected free function into existing code, and having a define along the lines of:

Code: [Select]
#define free myfree

in one of the header files that gets pulled into all libraries (including the String library). For the sake of a few dozen extra instructions you then have a workaround until the real library is fixed.
http://www.gammon.com.au/electronics

zoomkat

Quote
But the bug in question is something to do with the first (or last?) allocated block not being freed correctly, or something like that.


Then is there any way in the code to keep that particular block filled with nothing?
Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   8)

GoForSmoke

I took what Andy wrote to be saying there is no bug/problem. My error.
I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

pYro_65


global variables work better for me and I haven't heard of a good reason I should avoid them in my Arduino sketches.
Lefty


I can share at least one reason why you should reconsider globals. Here is a little sketch showing how a global can cause a very bad day.

This calculates the square of 2.

Code: [Select]

   //A global
   int i = 666;

   template <typename T> struct Base{
     Base( int i_NewVal ) : i( i_NewVal ) {return;}
     int i;
   };
   
   template <typename T> struct Squared : public Base<T>{
     Squared( int i_NewVal ) : Base<T>( i_NewVal * i_NewVal ) {return;}
     T Result() { return i; }
   };

  void setup()
    {
      Squared< long > s_Square( 2 );
     
      Serial.begin( 9600 );
      Serial.print( "2 squared = " );
      Serial.print( s_Square.Result() );
      return;
    }
   
  void loop(){return;}

Nick Gammon

Code: [Select]
   int i = 666;


I haven't even tried to run your sketch, but straight away, I sense trouble. ;)
http://www.gammon.com.au/electronics

tuxduino

@pyro

You sketch is not about globals, rather it warns of the perils one faces by using poorly named variables :)

pYro_65

The name of the variable could be something intuitive, I used 'i' for this example.
It does not affect the example. The sketch below works fine.

Code: [Select]
   //A global
   int i = 666;

  void setup()
    {
      int i = 2 * 2;
     
      Serial.begin( 9600 );
      Serial.print( "2 squared = " );
      Serial.print( i );
      return;
    }
   
  void loop(){return;}


In my previous example,
The global is a non-dependant name, it is satisfying a rule where non-dependant names in dependant types take the last definition seen. The compiler doesn't consider the base class during name lookup, even though its 'i' is the closer scope. This is quite different to the snippet above where the closer scope is setup::i which is also used.

So rather than receiving an error about 'i' being undefined in the class ( 'this->' is required to make the name dependant ), the previous definition of 'i' is silently used.

As a minimum, place the global in a namespace so it has to be explicitly used.

tuxduino

Quote
As a minimum, place the global in a namespace so it has to be explicitly used.


Very interesting posts. I would add as a minimum don't go against common practices by naming a global with a name usually "reserved" for narrow-scoped counters and array indexes. IOW, don't produce code that's confusing to _read_ in the first place. :)

PaulS

Quote
You sketch is not about globals, rather it warns of the perils one faces by using poorly named variables

I see it more as a problem with having local and global variables with the same name, and making assumptions about which will be used when.

Having local and global variables of the same name is rarely a good idea.

Nick Gammon

I going to agree with PaulS here. In your (rather obscure) example pYro_65 you set up a case where the compiler chose a global instead of a class variable by using the same name for both. To fix the sketch BTW you need to change the derived class to:

Code: [Select]

template <typename T> struct Squared :
public Base<T>{
  Squared( int i_NewVal ) :
  Base<T>( i_NewVal * i_NewVal ) {
    return;
  }
  T Result() {
    return Base<T>::i;
  }
};


Notice the qualification of "i" there. But you could say the same thing about virtually any variable. If you had a global i_NewVal and then misspelt i_NewVal in the constructor you would have a similar issue.
http://www.gammon.com.au/electronics

Go Up