SIGABRT в двоичном режиме чтения / записи - PullRequest
1 голос
/ 24 февраля 2012

Я написал очень маленький фрагмент кода и уже получил следующую ошибку:

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

Проблема в том, что я понятия не имею, о каком указателе говорит компилятор. Я передаю переменную по адресу в функции чтения / записи, но я никогда не освобождаю ее, насколько я знаю. Где ошибка в моем коде? Я запустил его с Утечками и Зомби, но ничего не получил.

Вот моя программа:

#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 ]

1 голос
/ 24 февраля 2012

Вы не можете прочитать объект, который содержит std :: string (или что-либо, что не является обычными данными) с помощью fin.read () -

Объект читается и записывается как потокбайтов, но std: string содержит указатель на память, которая хранится где-то еще и не записана с вашим fout.write () и не инициализирована должным образом с вашим fin.read ()

Это потому, что этоне правильно инициализирован с вашим fin.read (), что вы получаете ошибку кучи;когда объект выходит из области видимости, вызывается деструктор неправильно инициализированной std :: string и пытается освободить память, которой он не владеет.

Возможно, вы захотите написать собственный ввод / выводметод для вашего объекта и сохранить или загрузить его по частям.Для быстрого доступа к этому используйте библиотеку сериализации Boost.

1 голос
/ 24 февраля 2012

Вы не можете делать то, что делаете, просто потому, что std::string не может быть скопировано таким образом.Внутри объекта string выделяется память, а простая копия внешней структуры не делает то, что вы ожидаете.

Вам необходимо правильно сериализовать эту структуру.

1 голос
/ 24 февраля 2012
  1. Не используйте подчеркивания, пожалуйста
  2. Передайте объекты по ссылке: Bank(string& name), пожалуйста
  3. Это зло: fout.write((char *)&bank, sizeof(bank));
  4. Возможно, вы захотите написать << и >> операторы ostream вашего Bank класса.

Например:

friend std::ostream& operator<<(std::ostream &out, const Bank& b);
friend std::istream& operator>>(std::istream &out, const Bank& b);
1 голос
/ 24 февраля 2012

Поскольку ваш класс Bank содержит std :: string, вы не можете читать / записывать его как двоичный файл, как вы думаете. У std :: string есть внутренние указатели. Если вы пишете это как двоичный файл, вы просто будете писать указатели, а не фактическое содержимое строки. Аналогично, когда вы читаете строку, вы собираетесь читать указатель. В этом случае вы в конечном итоге получаете в качестве объекта bank и bank2 строки, указывающие на одну и ту же память, поэтому при освобождении этой памяти она освобождается дважды.

Вам понадобится другой способ записи данных вашего банка в файл. В этом случае подойдет простой файл ASCII с названием банка.

0 голосов
/ 24 февраля 2012

Функции-члены запись 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;
...