SIGABRT二进制读/写

时间:2012-02-24 15:38:20

标签: c++ memory serialization io

我写了一个非常小的代码片段,并且已经收到以下错误:

malloc: *** error for object 0x100100080: pointer being freed was not allocated

问题是,我不知道编译器在说什么指针。我将地址中的变量传递给读/写函数,但据我所知,我从未释放它。我的代码中的错误在哪里?我和Leaks and Zombies一起跑了,但什么都没有。

这是我的计划:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

class Bank
{
 private:
    string __name;

 public:
   Bank() 
   { 
      __name = ""; 
   }
   Bank(string name) 
   {
      __name = name; 
   }

    string getName() const { return __name; }
};


 int main (int argc, char * const argv[]) 
{
    Bank bank("Bank of America");
    Bank bank2;

    cout << "Bank1: " << bank.getName() << endl; 
    string filename = bank.getName() + ".bank";

    ofstream fout(filename.c_str(), ios::binary);
    if (fout.good())
      fout.write((char *)&bank, sizeof(bank));
    fout.close();

    ifstream fin(filename.c_str(), ios::binary);
    if (fin.good())
      fin.read((char *)&bank2, sizeof(bank2));
    fin.close();

    cout << "Bank2: " << bank2.getName() << endl;

    return 0;
}

5 个答案:

答案 0 :(得分:1)

因为您的Bank类包含std :: string,所以您无法像想象的那样将其读/写为二进制。 std :: string有内部指针。如果你把它写成二进制文件,你将只是编写指针而不是实际的字符串内容。同样,当你读取字符串时,你将要读一个指针。在这种情况下,您最终会使bank和bank2对象都具有指向同一内存的字符串,因此当释放该内存时,它将被释放两次。

您需要使用其他方式将银行数据写入文件。在这种情况下,带有银行名称的简单ASCII文件就可以了。

答案 1 :(得分:1)

你不能做你正在做的事情,因为std::string不能像那样被复制。在内部,string对象分配内存,外部结构的简单副本不符合您的预期。

您需要正确序列化此结构。

答案 2 :(得分:1)

  1. 请不要使用下划线,
  2. 通过引用传递对象:Bank(string& name),请
  3. 这是邪恶的:fout.write((char *)&bank, sizeof(bank));
  4. 您可能希望撰写<<课程的>>Bank ostream运算符。
  5. 例如:

    friend std::ostream& operator<<(std::ostream &out, const Bank& b);
    friend std::istream& operator>>(std::istream &out, const Bank& b);
    

答案 3 :(得分:1)

您无法使用fin.read()读取包含std :: string(或任何不是Plain Ol'数据的对象)的对象 -

该对象作为字节流读取和写入,但是std:string包含一个指向内存的指针,该指针存储在别处并且不是用你的fout.write()编写的,并且没有用你的fin.read正确初始化( )

这是因为你的fin.read()没有正确初始化你得到堆错误;当对象超出范围时,正在调用未正确初始化的std :: string的析构函数,并尝试释放它不拥有的内存。

您可能希望为对象编写自定义i / o方法,并逐个保存或加载它。有关执行此操作的快捷方式,请使用Boost序列化库。

答案 4 :(得分:0)

成员函数写入ostream,读取istream专门用于输入和输出二进制数据。如果您确实想要操作二进制数据,请使用以下命令:

ifstream fin(filename.c_str(), ios::in|ios::binary|ios::ate);
size = fin.tellg();
memblock = new char [size];
fin.seekg(0, ios::beg);

if (fin.good()){
   fin.read(memblock, size);
   fin.close();
}
delete[] memblock;