如何防止这些内存泄漏?

时间:2017-04-08 21:01:10

标签: c++ memory-leaks

我遇到了内存泄漏的巨大问题,我不知道在哪里放“删除”来摆脱它们。以下是我的代码的一部分,并且有一个完整的代码:https://pastebin.com/Wtk83nuH

string* startowa(int& rozmiar)
{
rozmiar = 5;
string* tablica = new string[rozmiar];

for (int i = 0; i < rozmiar; i++)
    tablica[i] = "text";
return tablica;
}

string* plusx(string* tab, int& rozmiar)
{
string tekst = "something";
string* tablica_3 = new string[rozmiar];
tablica_3[rozmiar - 1] = tekst;
for (int i = 0; i<rozmiar - 1; i++)
    tablica_3[i] = tab[i];

return tablica_3;
}

string* minusx(string* tab, int& rozmiar)
{
string* tablica_3 = new string[rozmiar];
for (int i = 0; i < rozmiar; i++)
    tablica_3[i] = tab[i];

return tablica_3;
}

int main()
{
int wybor = 1, rozmiar = 1;
string *tablica = startowa(rozmiar);

while (wybor != 55) {
    cin >> wybor;
    if (wybor == 1) {
        rozmiar++;
        tablica = plusx(tablica, rozmiar);
    }
    if (wybor == 6) wybor = 55;
    else {
        rozmiar--;
        tablica = minusx(tablica, rozmiar);
    }
    // there were other "ifs" but its just a part of the code
}
for (int i = 0; i < rozmiar; i++)
    cout << tablica[i] << endl;

delete[] tablica;
cin >> wybor;

getchar();

return 0;
}

3 个答案:

答案 0 :(得分:2)

内存泄漏是源代码中最不重要的问题。实际上,在您的示例中根本不需要堆分配。

以下是一些快速改进:
- 使用“std :: string”而不仅仅是字符串,我想你正在使用“using namespace std”
- 不要返回指向字符串的指针,只需声明一个字符串并将其返回 - 如果您没有返回它,请不要使用对int的引用作为函数参数 - 尽可能多地使用const - 将“string *”替换为“const string&amp;”如果你没有归还它 - 不要在堆上分配字符串(使用new),而是在堆栈上声明它 - 使用向量

您可以将此great site和Scott Meyers书籍用于其他C ++良好实践。

答案 1 :(得分:2)

为防止此类内存泄漏,请避免手动内存管理。有很多工具可供你使用。

例如,取你的字符串数组:

string* startowa(int& rozmiar) {
    rozmiar = 5;
    string* tablica = new string[rozmiar];

    // ...
}

这应该由std::vector取代。由于矢量跟踪它的大小,你不需要传递大小作为参考:

 std::vector<std::string> startowa() {
    // ...
    std::vector<std::string> tablica(5);

    // ...
}

然后,对数组进行操作的函数应该通过引用来获取有关副本的向量,并返回另一个向量。由于向量已经具有插入新元素的函数,因此plusx函数变为:

void plusx(std::vector<std::string>& tab) {
    std::string tekst = "something";
    tab.emplace_back(std::move(tekst));
}

您的minusx功能变为:

void minusx(std::vector<std::string>& tab) {
    tab.pop_back();
}

顺便说一句,使用向量,您可以通过替换主要中的调用来完全删除startowa函数:

// Was `string *tablica = startowa(rozmiar);`
std::vector<std::string> tablica(5, "text");

由于std::vector管理了内存本身,因此您无需在任何地方删除它。

如果您不想使用矢量,您可以一直使用std::unique_ptr<std::string[]>。代码的唯一区别是将tablica.get()发送到您的函数,并使用std::make_unique<std::string[]>(rozmiar)代替new std::string[rozmiar]

答案 2 :(得分:0)

正确答案is use std::vector。例如:

vector<string> startowa(int& rozmiar)
{
    rozmiar = 5;
    vector<string> tablica(rozmiar);

    for (int i = 0; i < rozmiar; i++)
        tablica[i] = "text";
    return tablica;
}

请注意按值返回。不要陷入以为returning by reference为止节省处理时间的陷阱。那个vector goes out of scope并在函数结束时被销毁。使用返回的引用,你可以期待的最好的是调用者在造成任何损害之前接收到大量垃圾并崩溃。

一个体面的编译器会在你返回vector的值时消除复制,如果编译器决定它不能,std::move will take care of that

vector也知道它有多大,无需rozmiar

现在......出了什么问题?我们来看看代码

int main()
{
    int wybor = 1, rozmiar = 1;
    string * tablica = startowa(rozmiar); 

startowa分配了一个字符串数组,并在tablica中存储了一个指向该数组的指针。

    while (wybor != 55)
    {
        cin >> wybor;
        if (wybor == 1)
        {
            rozmiar++;
            tablica = plusx(tablica, rozmiar);

plusx分配了一个新的字符串数组,一个指针返回并写入startowa返回的指针。 startowa的数组现在已经丢失,泄露,因为几乎无法再找到delete[]

在完成作业之前,我们需要delete[] tablica;。很明显,我们无法在调用plusx之前执行此操作,因为tablica是一个参数,因此我们需要存储一个临时值。

            string * temp = plusx(tablica, rozmiar);
            delete[] tablica;
            tablica = temp;

但是,如果出现意外情况并an exception is thrown怎么办?代码永远不会命中delete[],并且两个分配都会丢失。 vector为您处理所有这些。

回到代码

        }
        if (wybor == 6)
            wybor = 55;
        else
        {
            rozmiar--;
            tablica = minusx(tablica, rozmiar);

与上述相同的问题和解决方案。

        }
        // there were other "ifs" but its just a part of the code
    }
    for (int i = 0; i < rozmiar; i++)
        cout << tablica[i] << endl;

    delete[] tablica;

这里发布了一个不确定数量的分配。其余的都丢失了。

    cin >> wybor;

    getchar();

    return 0;
}