【问题标题】:I'm freeing memory twice - C++我正在释放内存两次 - C++
【发布时间】:2017-10-28 18:55:03
【问题描述】:

我已经完成了这个程序,我检查我的“日期”类是否正确。问题是当我运行我的测试程序时,它返回了以下错误:

  • `./bin/test' 中的错误:双重释放或损坏(fasttop):0x00000000019c07c0 *

这个类的工作是读取和存储一个“日期”(一年)和一些事件(分配在一个字符串数组中)。例如,此类的对象是:1998 EVENT1 EVENT2 EVENT3。

操作员>>读取下一个格式:1908#Fantasmagorie#驯悍记#盗贼之手#刺杀吉斯公爵#海边之旅

好吧,我的问题是我要删除一些指针两次或释放一些内存两次,我尝试了很多东西但我不知道如何解决它(正如你在我的代码中看到的那样,我有当我删除它们时,已经尝试将所有指针设置为 0。): 日期类.h

#ifndef _date_HISTORICA_
#define _date_HISTORICA_

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

class date{
private:
    int year;
    int eventsNum;
    int reserved;
    string * str;
    void resize(int r);
public:
    date();
    //date(int a, string *s, int n);
    date(const date& d);
    ~date();
    int getAge();
    void addEvent(string& s);
    friend ostream& operator<<(ostream& os, const date& d);
    friend istream& operator>>(istream& is, date& d);
};



#endif

日期类代码:

#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<date.h>

using namespace std;

void date::resize(int r)
{
    assert(r>=0);
    if(r!=this->reserved)
    {
     if(r!=0)
     {
        string * aux = new string[r];
        if(this->reserved>0)
        {
            int min=this->reserved<r?this->reserved:r;
            for(int i=0; i<min; i++)
                aux[i]=this->str[i];
            delete[] this->str;
            this->str=NULL;
        }
        this->str=aux;
        this->reserved=r;
        if(this->reserved<this->eventsNum)
            this->eventsNum=this->reserved;
     } else
     {
        if(this->reserved>0)
        {
            delete[] this->str;
            this->str=NULL;
        }
        this->year=0;
        this->eventsNum=0;
        this->reserved=0;
     }
    }
}

date::date() : year(0), eventsNum(0), reserved(0), str(0){}

date::date(const date& d)
{
    this->year=d.year;
    this->eventsNum=d.eventsNum;
    this->reserved=d.reserved;
    this->str=new string[this->reserved];
    for(int i=0; i<this->eventsNum; i++)
        this->str[i]=d.str[i];
}

date::~date()
{
    this->year=0;
    this->eventsNum=0;
    this->reserved=0;
    if(this->str)
    delete[] this->str;
    this->str=NULL;
}

int date::getAge(){return this->year;}

ostream& operator<<(ostream& os, const date& d)
{
    os << d.year;
    for(int i=0; i<d.eventsNum; i++)
        os << '#' << d.str[i];
    os << endl;
    return os;
}

void date::addEvent(string& s){
    if (this->eventsNum == this->reserved){
       if (this->eventsNum==0)
          resize(1);
       else
          resize(2*this->reserved);
    }
    this->str[eventsNum]=s;
    eventsNum++;
 }

istream& operator>>(istream& is, date& d)
{
    string line; char c;
    is >> d.year >> c;
    getline(is, line);

    int n=1;
    for(int i=0; i<line.length(); i++)
        if(line[i]=='#')
            n++;

    d.eventsNum=n;
    d.reserved=d.eventsNum;
    delete[] d.str;
    d.str=NULL;
    d.str=new string[n];

    stringstream ss(line);

    for(int i=0; i<n; i++)
        getline(ss, d.str[i], '#');
    return is;
}

测试程序类:

#include<iostream>
#include<fstream>
#include<cronologia.h>
#include<date.h>

using namespace std;

int main(int argc, char * argv[]){
    cout <<  "STATE: IN PROGRESS" << endl;
    cout << "TEST: (2)" << endl;
    date d;

    ifstream f("./data/name.txt");

    while(f >> d)
    {
        cout << d;
    }
    date d1;
    cin >> d1;
    d=d1;
    cout << d << endl;


}

示例文件(应按日期分类读取):

1900#Sherlock Holmes Baffled#The Enchanted Drawing
1901#Star Theatre#Scrooge, or, Marley's Ghost
1902#A Trip to the Moon
1903#The Great Train Robbery#Life of an American Fireman
1904#The Impossible Voyage
1905#Adventures of Sherlock Holmes; or, Held for Ransom
1906#The Story of the Kelly Gang#Humorous Phases of Funny Faces#Dream of a Rarebit Fiend
1907#Ben Hur#L'Enfant prodigue
1908#Fantasmagorie#The Taming of the Shrew#The Thieving Hand#The Assassination of the Duke of Guise#A Visit to the Seaside

对不起我的英语!!! :,(

【问题讨论】:

  • d=d1; = 你的重载赋值运算符和复制构造函数在哪里?您可能会发现这是一篇有趣的文章:The Rule of Three/Five/Zero
  • 重载的赋值运算符和复制构造函数已经完成。我将添加 .h 文件,以便您更好地查看它们。
  • 那会很有帮助。没有它们,真正的复制品是可疑的。
  • 谢谢。该标题没有显示任何声明的赋值运算符重载,更不用说实现了,这正是我的第一条评论引用的内容。没有它,将使用默认值,即浅拷贝成员变量(即您的指针)。您最终会得到两个指向相同数据的对象。阅读文章。它讨论了这个问题以及如何最好地解决它。如果您在此站点上搜索[c++] rule of three,您将获得大量 的点击以供参考。 (仅供参考,std::string 中的 std::vector 使 all 这一切都消失了)。
  • 阅读rule of five。顺便说一句,为什么str 应该是一个指针std::string-s 可以共享....

标签: c++


【解决方案1】:

由于您的代码中没有赋值重载,因此在行中

    d=d1;

d1 的所有成员将按值复制到新对象d。因此将有对象date 的两个副本,它们在其成员str 中具有相同的引用值。这两个最终将超出范围,并且都将被破坏。第一个将释放分配的内存,而另一个将尝试释放相同的引用,这就是您收到错误的原因。

【讨论】:

    【解决方案2】:

    你需要一个复制赋值运算符:

    void swap(date& other) 
    {
        using std::swap;
        swap(year, other.year);
        swap(eventsNum, other.eventsNum);
        swap(reserved, other.reserved);
        swap(str, other.str);
    }
    
    date::date(const date& d) : year(other.year), eventsNum(other.eventsNum), reserved(other.reserved), str(new string[other.reserved])
    {
        for(int i = 0; i < this->eventsNum; i++)
            this->str[i] = d.str[i];
    }
    
    date& date::operator = (const date& d)
    {
        swap(*this, d);
        return *this;
    }
    

    提供移动构造函数可能也不错..

    【讨论】:

    • 这个实现不是异常安全的,会产生内存泄漏并且不能正确处理自赋值。应改为使用复制和交换。
    • 如果this 分配了字符串,则会泄漏内存。
    • 不正确的实现...拷贝构造函数需要直接实现。然后可以使用 coy 构造函数和交换来实现赋值运算符。我建议您再次阅读 Herb Sutter 的Exceptional C++一书中的item 13
    • 删除了我的反对票,因为实施已修复。
    猜你喜欢
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2015-06-18
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多