【问题标题】:Memory Allocation - Using delete properly内存分配 - 正确使用删除
【发布时间】:2012-05-10 23:18:02
【问题描述】:

由于delete [] meanings;delete [] meanings;delete [] temp_meaning;,我的所有程序都崩溃了,当我删除这 3 行时它工作正常,所以可能我错误地使用了 delete ... 有人可以在这里启发我吗?

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

class Expression {

    char *word_with_several_meanings; // like "bank", "class"
    char **meanings; // a pointer to a pointer stores all meanings
    int meanings_ctr; // meanings counter

    //-----------FUNCTIONS------------------------------------------------
public:
    void word(const char* = NULL );
    void add_meaning(char * = NULL);
    char* get_word();
    int get_total_number_of_meanings();
    char* get_meaning(int meanx = 0);
    Expression(int mctr = 0); // CTOR
    ~Expression(); // DTOR
};

Expression::Expression(int mctr ) {
    meanings_ctr = mctr;    // Setting the counter to 0
    meanings = new char * [meanings_ctr]; // Allocate Space for meanings
}

Expression::~Expression() {

    while(meanings_ctr-->0){
    delete meanings[meanings_ctr];
    }
    delete [] meanings; // Deleting the memory we allocated
    delete [] word_with_several_meanings; // Deleting the memory we allocated
}

void Expression::word(const char *p2c )
{

    word_with_several_meanings = new char[strlen(p2c)+1];
    // copy the string, DEEP copy
    strcpy(word_with_several_meanings, p2c);
}

void Expression::add_meaning( char  * p2c)
{

    //meanings[ meanings_ctr ] = new char [strlen(p2c) + 1];
    //strcpy(meanings[ meanings_ctr++ ] , p2c);
    // temp 
    if (meanings_ctr < 1){
    meanings[ meanings_ctr ] = new char [strlen(p2c) + 1];
    strcpy(meanings[ meanings_ctr++ ] , p2c);
    }
    else {
int temp_ctr;
    char **temp_meaning;
    temp_meaning = new char * [meanings_ctr-1];
    for(temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
        temp_meaning[temp_ctr] = new char [strlen(meanings[ temp_ctr ]) + 1];
            strcpy(temp_meaning[temp_ctr], meanings[ temp_ctr ]);
    }
    for (temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
            delete meanings[temp_ctr];

    }
    delete [] meanings;

    meanings = new char * [meanings_ctr];
    for(temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
        meanings[ temp_ctr ] = new char [strlen(temp_meaning[temp_ctr]) + 1];
            strcpy(meanings[ temp_ctr ], temp_meaning[temp_ctr]);
    }
    meanings[ meanings_ctr ] = new char [strlen(p2c) + 1];
    strcpy(meanings[ meanings_ctr ] , p2c);
            for (temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
            delete temp_meaning[temp_ctr];
    }
    delete [] temp_meaning;
            meanings_ctr++;
    }


}

char * Expression::get_meaning( int meanx )
{

    return *(meanings+meanx);

}

char * Expression::get_word()
{

    return word_with_several_meanings;

}

int Expression::get_total_number_of_meanings()
{
    return meanings_ctr;
}


int main(void) {
    int i;
    Expression expr;
    expr.word("bank");
    expr.add_meaning("a place to get money from");
    expr.add_meaning("b place to sit");
    expr.add_meaning("4 letter word");
    expr.add_meaning("Test meaning");
    cout << expr.get_word() << endl;

    for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
            cout << " " << expr.get_meaning(i)  << endl;
    Expression expr2;
    expr2.word("class");
    expr2.add_meaning("a school class");
    expr2.add_meaning("a classification for a hotel");
    expr2.add_meaning("Starts with C");
    cout << expr2.get_word() << endl;
    for( i = 0; i<expr2.get_total_number_of_meanings(); i++)
            cout << " " << expr2.get_meaning(i) << endl;

    Expression expr3;
    expr3.word("A very long test");
    char str[] = "Meaning_    ";
    for(int kx =0; kx<31; kx++){
            str[8] = ('A'+kx);
            expr3.add_meaning(str);
    }

    cout << expr3.get_word() << endl;
    for( int i = 0; i<expr3.get_total_number_of_meanings(); i++)
            cout << " " << expr3.get_meaning(i) << endl;
    return 0;
}

【问题讨论】:

  • 尝试删除像 while(meanings_ctr-->0){ delete meanings[meanings_ctr]; 这样的循环} 并且只在含义等上使用 delete[]...
  • 不使用std::string 和STL 容器有什么原因吗?
  • new 必须是 delete'd。什么是 new[],必须是 delete[]'d。 blogs.msdn.com/b/oldnewthing/archive/2004/02/03/66660.aspx
  • 注。你使用delete temp_meaning[temp_ctr]——应该是delete [] temp_meaning[temp_ctr]
  • 所有菜鸟的原因是我是初学者,这是我的第一门 C++ 课程是的,我来自 C 世界,因为我刚在学校通过 C,我们开始使用 C++,例如我从很多人那里听到矢量可以使用等,但我不能,因为教授还没有介绍它,并希望我们以某种方式发明我们自己的向量类来更好地学习 C++ :)

标签: c++ memory new-operator allocation delete-operator


【解决方案1】:

该程序显示出来自以下语句的内存损坏迹象:

    meanings_ctr = mctr;    // Setting the counter to 0
    meanings = new char * [meanings_ctr]; // Allocate Space for meanings

    meanings = new char * [meanings_ctr];

由于 add_meaning() 包含以下代码:

if (meanings_ctr < 1){
   meanings[ meanings_ctr ] = new char [strlen(p2c) + 1];

您实际上是在含义[0] 上写的,而您为它分配了 0 个字节。由于 C 中的索引从 0 开始,对于在 max_index 具有最高索引的数组,您需要分配 max_index+1 元素。对于 max_index = 0 的数组,您需要分配 1 个元素。

换句话说,您需要分配meanings = new char * [meanings_ctr + 1] 而不是new char * [meanings_ctr],以及temp_meaning = new char * [meanings_ctr] 而不是new char * [meanings_ctr - 1]

对于deletedelete[]的使用,一般规则是new分配的应该用delete释放,new[]分配的应该用delete[]销毁。上面有一个线程:delete vs delete[] operators in C++。在how does delete know it is an array的答案中可以找到一些好的背景。

以下是如何在不使用任何昂贵的工具或难以学习的工具的情况下调试程序。

如果您将调试打印添加到构造函数和析构函数中,如下所示:

Expression::Expression(int mctr ) {
    meanings_ctr = mctr;    // Setting the counter to 0
    meanings = new char * [meanings_ctr]; // Allocate Space for meanings
    cout << "[debug] allocated " << sizeof(char*)*meanings_ctr << " bytes @" << 
             hex << meanings << dec << endl;
}

还有

Expression::~Expression() {
    while(meanings_ctr-- > 0){
//       if(meanings[meanings_ctr]) delete [] (meanings[meanings_ctr]);
    }
    cout << "[debug] to deallocate @" << hex << meanings << dec << endl;
//   delete [] meanings; // Deleting the memory we allocated
//    delete [] word_with_several_meanings; // Deleting the memory we allocated
}

同样在 add_meaning() 中,你得到 ​​p>

[debug] allocated 0 bytes @0x804c008
[debug] to deallocate @0x804c008
[debug] allocated 4 bytes @0x804c078
 ...
[debug] allocated 120 bytes @0x804fa78
[debug] to deallocate @0x804fa78
[debug] to deallocate @0x804c260
[debug] to deallocate @0x804c150

这里看起来令人担忧的是allocated 0 bytes。由于 add_meanings() 中的代码包含:

if (meanings_ctr < 1){
meanings[ meanings_ctr ] = new char [strlen(p2c) + 1];

它使用未分配的内存@meanings[0] 并导致损坏。

这里是所有累积变化的参考:

25c25
<     meanings = new char * [meanings_ctr]; // Allocate Space for meanings
---
>     meanings = new char * [meanings_ctr + 1]; // Allocate Space for meanings
30,31c30,31
<     while(meanings_ctr-->0){
<     delete meanings[meanings_ctr];
---
>     while(meanings_ctr-- > 0){
>         delete [] meanings[meanings_ctr];
58c58
<     temp_meaning = new char * [meanings_ctr-1];
---
>     temp_meaning = new char * [meanings_ctr ];
64c64
<             delete meanings[temp_ctr];
---
>          delete [] meanings[temp_ctr];
69c69
<     meanings = new char * [meanings_ctr];
---
>     meanings = new char * [meanings_ctr + 1];
76,77c76,77
<             for (temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
<             delete temp_meaning[temp_ctr];
---
>     for (temp_ctr =0; temp_ctr<meanings_ctr;temp_ctr++){
>            delete [] temp_meaning[temp_ctr];

【讨论】:

  • 我刚改了code含义=新字符*[含义_ctr+1]; temp_meaning = 新字符 * [meanings_ctr]; code 但没有帮助:(
  • cmets 中还提到了一些其他的事情,我还没有回答:使用delete [] (meanings[ctr]) 而不是delete meanings[ctr]。括号很重要。添加了一个包含所有更改的差异。
  • 您能否详细说明一下 - 为什么括号 ()delete [] (meanings[ctr]) 中很重要?
  • @DCoder 不是真的。我不在内存中保存 C++ 运算符优先级表,并在有疑问时加上括号。
  • 当你像meanings = new char * [0]一样分配0字节时,它是0字节,写入meanings[0] = new char[x]你需要sizeof(char*)字节。由于 C 中的索引从 0 开始,正确的分配将 1 添加到最后一个元素的索引。至于delete[],如果你分配new使用delete,但如果分配new[]一个delete[]是必需的。
【解决方案2】:

你必须来自 C 世界,你不会在 C++ 程序中找到任何 char* 来存储单词...你应该看看 std::string,它会启发你的一天,我可以向你保证.

顺便说一句,在 C++ 中,我们倾向于摆脱所有那些 deletedelete [],您也许应该选择一本好的 C++ 书籍并学习正确的 C++,而不是 30 年前使用的带有类的 C。

【讨论】:

  • 嘘。根本不解决问题。最后我检查了一下,delete 仍然是语言中必不可少且经常使用的部分。
  • +1。它不再那么频繁地使用了,因为我们有了智能指针。
  • 很好,但是尝试学习该语言的人不可能直接跳到智能指针,并且永远不会学习如何“以老式方式”去做,哈哈。他们将被排除在循环WRT世界上大多数的C++代码之外,以及不希望使用智能指针的情况。
  • @goldilocks:这就是为什么我建议他读一本好的 C++ 书,这比在这里阅读任何答案都更有用。即使显然需要知道用 C++ 编码的“旧方式”,我还是建议你看一本最近的书,介绍 C++ 而不是从学习 C 开始,然后是对象的东西。对我来说,像 C++ 入门书(第 5 版即将出版)或 Programming -- Principles and Practice Using C++(没读过那本书,但如果是 Stroustrup 写的,那一定很好)真的很值得购买,而且/或阅读。
  • 并不是我的意思是居高临下 ;) ;) 但我现在更了解你是如何成为这样的语言权威的,你可以做出这些笼统的陈述(同时回避真正的问题)。听起来像 OP 是在一门课程中,如果教授希望他们学习内存管理,那可能很好。充其量:这不是答案,而是评论
猜你喜欢
  • 2017-05-08
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
相关资源
最近更新 更多