C++ C++;内存泄漏,我可以';找不到

C++ C++;内存泄漏,我可以';找不到,c++,memory-management,memory-leaks,microcontroller,C++,Memory Management,Memory Leaks,Microcontroller,我这里有一个关于粒子光子的小示例程序,它有一个我无法理解的内存缺陷 它的作用:加载一个带有小字符串块的缓冲区,将大缓冲区转换回字符串。然后它创建一组对象,这些对象只是缓冲区小块的包装器。它会重复执行此操作,在setup()之后我不会分配任何新内存,但内存会缓慢下降,直到崩溃 main.cpp 包括,变量声明 设置功能、分配内存、初始分配 编辑: 这是我面临的一个真正的问题,我不知道为什么它会被否决。帮帮我,我怎么能说得更清楚?我不愿意收缩代码,因为它模仿了一个更大的程序的许多方面,只是简单地建模

我这里有一个关于粒子光子的小示例程序,它有一个我无法理解的内存缺陷

它的作用:加载一个带有小字符串块的缓冲区,将大缓冲区转换回字符串。然后它创建一组对象,这些对象只是缓冲区小块的包装器。它会重复执行此操作,在setup()之后我不会分配任何新内存,但内存会缓慢下降,直到崩溃

main.cpp 包括,变量声明 设置功能、分配内存、初始分配 编辑:
这是我面临的一个真正的问题,我不知道为什么它会被否决。帮帮我,我怎么能说得更清楚?我不愿意收缩代码,因为它模仿了一个更大的程序的许多方面,只是简单地建模。我想保留代码的结构,以防这个bug是一个紧急属性

所以,经过一些测试后,我想向给出正确答案的罗斯舒尔茨(Russ Schultz)大喊一声。如果您想正式发布解决方案,我很乐意将其标记为正确

内存错误是由于分配char buffer\u容器而没有考虑null终止字符引起的,这意味着我正在加载一个太大的字符串。(不完全确定这为什么会导致错误并且不会抛出错误?)

然而,在另一个网站上,我也收到了以下建议:

字符串块;
对于(字符i=0;i<200;i++){
int index=rand()%字母范围;
chunk.append(字母表.substr(索引,1));
//strcat(缓冲区、字母表、子字符串(索引、索引+1));
num_chars++;
}
我觉得这个循环很可疑。您需要依靠stringappend方法根据需要增长块,但您知道您将运行该循环200次。为什么不使用stringreserve方法来分配那么多空间呢?我敢打赌,当您调用realloc时,添加的每个新字符都会占用大量内存,这可能会导致内存碎片


这最终不是解决方案,但知道这一点可能会很好

始终考虑字符串终止符:

    DummyClass(string input){
        _container = new char[input.length()];
        strcpy(_container, input.c_str());
    }
分配太少的一个字节来保存输入字符串和终止符,然后将其复制到其中。最后附加的
\0
正在覆盖某些内容,这很可能是成功地将分配的内存片段重新集成回堆所需的元数据。我真的很惊讶它没有崩溃


可能不会每次分配都发生这种情况(仅当您溢出到一个新的8字节对齐块中时才会发生),但一次就足够了:)

对于这种格式来说,代码太多了。请出示一张支票。valgrind等工具可以帮助您缩小问题范围,使用调试信息编译代码以获得更精确的结果。这不会导致泄漏,而是在
~DummyClass()
replace
delete\u容器中使用
删除[]\u容器不确定这是否会导致泄漏,但分配
\u container=new char[input.length()]可能会导致不好的事情发生
(您没有为
\0
分配空间)作为一种调试策略,为每个
DummyClass()
添加一个全局对象id。每次创建新对象时,增加id并将其添加到地图或所选集合中。删除时,请将其从集合中删除。一段时间后,检查以确保集合为空。这样,您可以确保删除正在创建的每个对象。另一个小问题是析构函数会盲目删除
\u容器
。如果您有一个使用默认构造函数创建的对象,
\u container
未定义,因此您的行为将未定义。我不认为上述代码中会发生这种情况,但有一点需要担心。当您在空闲存储区中溢出缓冲区时,它可能会损坏有关已分配内存或其他已分配内存的信息。结果可能是崩溃、泄漏或数据损坏。取决于被覆盖的数据是什么。为什么人们一直对我投反对票。我很困惑。我认为这个网站的目的是提问和传播知识。我在这里所做的就是问一个关于我所遇到的问题的问题,尽量表现得友善,并对答案给予肯定。我的名声已经很低了;我觉得自己受到了极不公平的对待,我绝对不会被鼓励去寻求更多的帮助。我对这个问题投了更高的票,因为你显然付出了很多努力,尽管我不建议你在问题或答案中添加太多的元评论(大多数读者对此不感兴趣,而且经常被删掉)。对于您的答案,我倾向于建议,如果您正在添加一个附录,但其他人广泛解决了它,您可以将其设置为社区Wiki,这意味着对它的任何投票都不会影响您的分数。(我认为C++标签确实对MCVE更严格——这可能是那些倾向于低级语言的人的苛刻本性。如果你得到了几张下注,那么不用担心——评论说不幸的人可以吸引更多的人!)
bool delete_objects()
{
    Serial.println("deleting objects in 'store'");
    for(auto iter = store.begin(); iter != store.end(); iter++)
    {
        delete iter->second;
        iter->second = nullptr;
    } 
    store.clear();

    if(store.empty())
        return true;
    else
        return false;
}
void setup()
{
    Serial.begin(9600);
    Serial1.begin(38400);
    delay(2000);

    buffer = new char[9000];
    alphabet = string("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$^&*()_-?/><[]{}|");
    alphabet_range = alphabet.length() - 1;
    state = STATE_INIT;
    num_chars = 0;
}
void loop()
{
    switch(state){
        case STATE_INIT: {

            strcpy(buffer, "");
            state = STATE_LOAD_BUFFER;
            delay(1000);
            break;

        }
        case STATE_LOAD_BUFFER: {

            if(num_chars < 6000){
                string chunk;
                for(char i = 0; i < 200; i++){
                    int index = rand() % alphabet_range;
                    chunk.append(alphabet.substr(index, 1));
                    num_chars++;
                }
                strcat(buffer, chunk.c_str());
            }
            else{
                num_chars = 0;
                state = STATE_PREP_FOR_DESERIALIZE;
            }
            delay(500);
            break;

        }
        case STATE_PREP_FOR_DESERIALIZE: {

            Serial.println("\nAttempting to delete current object set...");
            delay(500);
            if(delete_objects())
                Serial.println("_delete_objects succeeded");
            else {
                Serial.println("_delete_objects failed");
                break;
            }
            state = STATE_FAKE_DESERIALIZE;
            delay(1000);
            break;

        }
        case STATE_FAKE_DESERIALIZE: {

            string buff_string(buffer);
            if(buff_string.length() == 0){
                Serial.println("Main:: EMPTY STRING CONVERTED FROM BUFFER");
            }

            int index = 0;
            int key = 1;
            while(index < buff_string.length())
            {
                int amount = (rand() % 50) + 5;
                DummyClass* dcp = new DummyClass(buff_string.substr(index, amount));
                store[key] = dcp;
                index += amount;
                key++;
            }
            state = STATE_FINISH_RESTART;
            delay(1000);
            break;

        }
        case STATE_FINISH_RESTART: {

            state = STATE_INIT;
            break;

        }
    }

}
using namespace std;

class DummyClass {
    private:
        char* _container;

    public:
        DummyClass(){
        }

        DummyClass(string input){
            _container = new char[input.length()];
            strcpy(_container, input.c_str());
        }

        ~DummyClass(){
            delete _container;
            _container = nullptr;
        }

        char* ShowMeWhatYouGot(){
            return _container;
        }
};
            string chunk;
            for(char i = 0; i < 200; i++){
                int index = rand() % alphabet_range;
                chunk.append(alphabet.substr(index, 1));
                // strcat(buffer, alphabet.substring(index, index + 1));
                num_chars++;
            }
    DummyClass(string input){
        _container = new char[input.length()];
        strcpy(_container, input.c_str());
    }