内存泄漏错误

Memory leak error?

本文关键字:错误 泄漏 内存      更新时间:2023-10-16

对于动态内存和复制构造函数的一个简单赋值,我的教授给我们分配了一个简单的赋值,但在第二次delete []发生时,我遇到了一个错误。

头文件:

class Stream {
    int len;
    char *hold;
    char* newmem(int);
public:
    Stream ();
    Stream (int);
    Stream(const char *);
    ~Stream ( );
    void operator=(const Stream &);
    Stream(const Stream &);
    friend void show(Stream);
    void operator<<(const char*);
};

它应该相当简单。这是我的代码:

#include <iostream>
#include <new>
#include <cstring>
using namespace std;
#include "stream.h"
char* Stream::newmem(int x) {
    char * tmp;
    try {
        tmp = new char[x];
    }
    catch(std::bad_alloc) {
        tmp = NULL;
    }
    if(tmp)
        cout << "newmem:  " << (void *) tmp << endl;
    return tmp;
}
Stream::Stream ( ) {
    len = 1000;
    hold = newmem(len);
    if (hold)
        strcpy (hold, "");
}
Stream::Stream(int n) {
    len = n;
    hold = newmem(len);
    if (hold)
        strcpy (hold,"");
}
Stream::Stream(const char * dat) {
    len = strlen(dat) +1;
    hold = newmem(len);
    if (hold)
        strcpy(hold,dat);
}
Stream::Stream(const Stream &from) {
    cout << "in the copy constructor, allocating new memory..." << endl;
    cout << "original pointer address is: " << (void *) from.hold << endl;
    cin.get( );
    len=from.len;
    hold=newmem(len +1);
    cout << "new pointer address is: " << (void *) hold << endl;
    cin.get( );
    if(hold)
        strcpy (hold,from.hold);
}
Stream::~Stream ( ) {
    cout << "destruct:  " << (void *) hold << endl;
    cin.get( );
    if (hold)
        delete [] hold;
}
void Stream::operator= (const Stream &from) {
    if(hold)
        delete [ ] hold;
    len = from.len;
    hold=newmem(len +1);
    if (hold)
        strcpy(hold,from.hold);
}
void show (Stream prt) {
    cout << "String is: " << prt.hold << endl << "Length is: " << prt.len << endl;
}
void Stream::operator<< (const char *data) {
    int dlen = strlen(data);
    for (int i=0 ; i<=len && i<=dlen ; i++) {
        hold[i] = data[i];
    }
}
int main( ) {
   char data[ ] = "Growing up it all seems so one-sided;"
                  "Opinions all provided;"
                  "The future pre-decided;"
                  "Detached and subdivided;"
                  "In the mass production zone!"
                  "-Neil Peart- "Subdivisions"";
   Stream x1, x2(25), x3;
   x1 << data;
   x2 << data;
   show(x1);
   show(x2);
   x3 = x2;
   show(x3);
   return 0;
}

和我的输出/错误:

在复制构造函数中,正在分配新内存。。。原始指针地址为:0x804c008新指针地址为:0x804c808字符串是:在成长过程中,一切似乎都是片面的;所有提供的意见;未来是预先决定的;分离的和细分的;在量产区-Neil Peart细分"长度为:1000析构函数:0x804c808在复制构造函数中,正在分配新内存。。。原始指针地址为:0x804c3f8新指针地址为:0x804c808字符串是:在成长过程中,一切似乎都是如此长度为:25析构函数:0x804c808***glibc检测到***a.out:free((:无效指针:0x0804c808***

operator<<中的for循环有两个关闭一个错误:

for (int i=0 ; i<=len

允许i==len,但hold的唯一有效索引是0..(len-1)。所以,你可以在结尾写一个。

其次,正如thiton所指出的,即使有空间,它也不会复制终止符。


一个正确的实现可能看起来像:

void Stream::operator<< (const char *data) {
    int source_len = strlen(data);
    int copy_len = min(source_len, len-1); // allow for terminator
    for (int i=0; i<copy_len; i++) {
        hold[i] = data[i];
    }
    hold[copy_len] = '';
}

尽管最好是简单地使用CCD_ 7。


请注意,使用半开(或超过末尾的一个(范围的习惯用法不仅在直接数组索引中是标准的,而且在C++迭代器中也是标准的。所以,你应该一直期待看到

for (i=0; i<n; ++i) {

for (i = begin; i != end; ++i) {

并且通常应该将像你这样的闭环视为需要进一步调查的气味。

首先有一点自助建议:捕获内存访问错误的最重要工具是valgrind。在程序上运行它,每次尝试访问未分配或未初始化的内存时都会收到警告。它不能代替知识,但它是下一个最好的东西。

虽然我得到的输出与你不同,但错误似乎在这里相互作用:

  1. operator<<在范围检查中有一个"一比一"错误。它写了一个字节太多(hold[len](
  2. operator<<从不写入终止的空字节。这两个错误都由x2 << data调用
  3. 当复制构造函数试图从x2复制字符串时,strcpy找不到终止的空字节,并且从x2.hold的末尾开始读取,并从x3.hold的末尾开始写入。后者有可能导致无限制的腐败,并可能导致您的错误

无论何时处理C字符串,都要确保正确地终止。固定版本为:

void Stream::operator<< (const char *data) {
    int dlen = strlen(data);
    hold[len-1] = 0;
    for (int i=0 ; i < len-1 && i <= dlen ; i++) {
         hold[i] = data[i];
    }
}

或者,使用std库:

void Stream::operator<< (const char *data) {
    strncpy(hold, data, len);
    hold[len-1] = 0;
}