Thread: String Vector Class -> data persists on heap memory?

  1. #1
    Registered User
    Join Date
    Sep 2022
    Posts
    8

    Lightbulb String Vector Class -> data persists on heap memory?

    Hello,

    I use this following function (on a microcontroller) to split a string into parts by using a delemiter.

    E.g.:

    Code:
    std::vector<std::string> parts = splitStringToVectorArray("String1;String2;String3", ";");
    The function works, but every time I call the function, data keeps persist on the heap memory. So I will run out of memory at all.

    I read that this problem could belong to the push_back command.
    So my question, is there any command missing in the function to release the used heap memory, or is something else wrong?

    Code:
    std::vector<std::string> splitStringToVectorArray(const std::string &inputString, const std::string &delimiter)  
        {
    
            std::vector<std::string> vectorArray;
            if (inputString.empty() || delimiter.empty())
            {
                vectorArray.push_back(inputString);
                return vectorArray;
            }
            size_t initiation = 0;
            size_t position;
            while ((position = inputString.find(delimiter, initiation)) != std::string::npos)
            {
                std::string stringValue = inputString.substr(initiation, position - initiation);
                if (!stringValue.empty())
                {
                    vectorArray.push_back(stringValue);
                }
                initiation = position + delimiter.length();
            }
            if (initiation < inputString.length())
            {
                vectorArray.push_back(inputString.substr(initiation));
            }
    
            return vectorArray;
        }
    Thanks, Michael

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    How are you determining that you have a memory leak?

    As written, it seems well behaved.
    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    
    std::vector<std::string> splitStringToVectorArray(const std::string &inputString, const std::string &delimiter)  
    {
    
        std::vector<std::string> vectorArray;
        if (inputString.empty() || delimiter.empty())
        {
            vectorArray.push_back(inputString);
            return vectorArray;
        }
        size_t initiation = 0;
        size_t position;
        while ((position = inputString.find(delimiter, initiation)) != std::string::npos)
        {
            std::string stringValue = inputString.substr(initiation, position - initiation);
            if (!stringValue.empty())
            {
                vectorArray.push_back(stringValue);
            }
            initiation = position + delimiter.length();
        }
        if (initiation < inputString.length())
        {
            vectorArray.push_back(inputString.substr(initiation));
        }
    
        return vectorArray;
    }
        
    int main()
    {
        std::vector<std::string> parts = splitStringToVectorArray("String1;String2;String3", ";");
        std::cout << parts[0] << std::endl;
    }
    
    
    $ g++ -g baz.cpp
    $ valgrind ./a.out 
    ==95652== Memcheck, a memory error detector
    ==95652== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==95652== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
    ==95652== Command: ./a.out
    ==95652== 
    String1
    ==95652== 
    ==95652== HEAP SUMMARY:
    ==95652==     in use at exit: 0 bytes in 0 blocks
    ==95652==   total heap usage: 6 allocs, 6 frees, 73,976 bytes allocated
    ==95652== 
    ==95652== All heap blocks were freed -- no leaks are possible
    ==95652== 
    ==95652== For lists of detected and suppressed errors, rerun with: -s
    ==95652== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Sep 2022
    Posts
    8
    Thx for your work!

    I use:

    Code:
    Serial.println("Free Heap: "+String(ESP.getFreeHeap()));
    to get free Heap

    I run the function as a method in class on a ESP32.


    I found this article, may be a heap fragmentation problem?

    Using the C++ Standard Template Library with Arduino | Chris Claxton's Blog
    Last edited by MichaelMMs; 11-05-2022 at 04:30 PM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    It could be.
    Memory constrained systems are far more reliant on solid library implementations doing the right thing.

    Is it easy/possible for you to try those alternative STL implementations?

    Where are you getting inputString from?
    What is the lifetime of the parts result?

    If you have a much simpler function, do you see the same heap erosion?
    Code:
    std::vector<std::string> splitStringToVectorArray(const std::string &inputString, const std::string &delimiter)  
        {
            std::vector<std::string> vectorArray;
            vectorArray.push_back("test");
            return vectorArray;
        }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Sep 2022
    Posts
    8
    Hi Salem,

    your second function behaves the same.
    The input string comes from a global running task, so no user input string,

    the output of the function goes to a LCD Class to be displayed on screen.
    This LCD-Class needs a const char * as input, so I use the convert function vectorArrayToCharPointer.

    Normally after the u8g2.drawUTF8 is done the pointer char will be deleted from heap by the u8g2.sendBuffer(); command.


    Here a short test without using external inputs.

    Code:
     std::vector<std::string> splitStringToVectorArray(const std::string &inputString, const std::string &delimiter)
        {
            std::vector<std::string> vectorArray;
            vectorArray.push_back("test");
            return vectorArray;
        }
    
        const char *vectorArrayToCharPointer(std::string s)
        {
    
            char *pc = new char[s.size() + 1];
            strcpy(pc, s.c_str());
            return pc;
        }
        
        
          void displayInfoMultiline(String infoString, uint8_t fontUsed = 3)
        {
    
    
    
            std::vector<std::string> test2 = splitStringToVectorArray("asd;asd;asd", ";");
             
    
            ...
       
                 
                
                u8g2.clearBuffer();
                u8g2.drawUTF8(0, ySpace, vectorArrayToCharPointer(test2[0]));
                u8g2.sendBuffer();
             
        }


    Four calls result:

    Free Heap: 340064
    Free Heap: 340040
    Free Heap: 340016
    Free Heap: 339992


    I coded a new Split function without vector, now it works.
    Last edited by MichaelMMs; 11-06-2022 at 11:05 AM.

  6. #6
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    277
    Quote Originally Posted by MichaelMMs View Post
    Hi Salem,

    your second function behaves the same.
    The input string comes from a global running task, so no user input string,

    the output of the function goes to a LCD Class to be displayed on screen.
    This LCD-Class needs a const char * as input, so I use the convert function vectorArrayToCharPointer.

    Normally after the u8g2.drawUTF8 is done the pointer char will be deleted from heap by the u8g2.sendBuffer(); command.


    Here a short test without using external inputs.

    Code:
     std::vector<std::string> splitStringToVectorArray(const std::string &inputString, const std::string &delimiter)
        {
            std::vector<std::string> vectorArray;
            vectorArray.push_back("test");
            return vectorArray;
        }
    
        const char *vectorArrayToCharPointer(std::string s)
        {
    
            char *pc = new char[s.size() + 1];
            strcpy(pc, s.c_str());
            return pc;
        }
        
        
          void displayInfoMultiline(String infoString, uint8_t fontUsed = 3)
        {
    
    
    
            std::vector<std::string> test2 = splitStringToVectorArray("asd;asd;asd", ";");
             
    
            ...
       
                 
                
                u8g2.clearBuffer();
                u8g2.drawUTF8(0, ySpace, vectorArrayToCharPointer(test2[0]));
                u8g2.sendBuffer();
             
        }


    Four calls result:

    Free Heap: 340064
    Free Heap: 340040
    Free Heap: 340016
    Free Heap: 339992


    I coded a new Split function without vector, now it works.
    Your vectorArrayToCharPointer function is the memory leak. You don't need to allocate anything anyway. Just call test2[0].c_str() and you'll get a pointer to the bytes of the string.

  7. #7
    Registered User
    Join Date
    Sep 2022
    Posts
    8
    hi Sir Galahad,

    thanks, you are right.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. char* ptr="HELLO"; String Literal:Stack/Heap/Data Segment
    By forumuser in forum C Programming
    Replies: 9
    Last Post: 09-20-2007, 04:53 AM
  2. Memory Allocation In A String Class
    By mike_g in forum C++ Programming
    Replies: 13
    Last Post: 09-18-2007, 10:34 AM
  3. how get string vector from class in file?
    By tord in forum C++ Programming
    Replies: 3
    Last Post: 06-17-2005, 09:58 AM
  4. Vector data in class?
    By Imperito in forum C++ Programming
    Replies: 4
    Last Post: 05-11-2002, 03:24 PM

Tags for this Thread