Memory leak - need help finding
Alright guys, I have a class called Bible. I have a memory leak when I create a new Bible object (being a pointer), then delete the object, the recreate it using a different file bible source file for the constructor parameter.
It's about 4.5 - 5MB, and I don't know what I'm doing wrong. I also have Book, Chapter, and Verse classes which go along with the Bible class. It's all a tree structure.
I'm thinking maybe it's cause a lot of my class members are not pointers, just normal stack variables, so they're not being deleted properly when the object is destroyed...?
Here's the source file. Any insight would be wonderful.
*EDIT*
nevermind the source file, I'll just post the code here.
Code:
/******************************************************************************
*
* This file is part of BibleReader.
*
* BibleReader is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef BIBLESTRUCTURES_H
#define BIBLESTRUCTURES_H
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <queue>
using namespace std;
// class prototypes
class SearchResult;
class Verse;
class Chapter;
class Book;
class Bible;
// constants
const int LENGTH_BYTES = 2;
const int LOCATION_BYTES = 4;
const int COUNT_BYTES = 2;
class SearchResult
{
private:
int book;
int chapter;
int verse;
public:
SearchResult(int b, int c, int v)
{
book = b;
chapter = c;
verse = v;
}
~SearchResult()
{
}
const int GetBook() const
{
return book;
}
const int GetChapter() const
{
return chapter;
}
const int GetVerse() const
{
return verse;
}
};
class Verse
{
private:
int pos;
string text;
public:
Verse(const int p)
{
pos = p;
}
Verse(const int p, string t)
{
pos = p;
text = t;
}
~Verse()
{
}
const int GetVersePos() const
{
return pos;
}
string GetText()
{
return text;
}
};
class Chapter
{
private:
int pos;
int nVerses;
vector<Verse*> verse_list;
public:
Chapter(const string *buffer, long p);
~Chapter()
{
}
const int GetVerseCount() const
{
return nVerses;
}
const int GetChapterPos() const
{
return pos;
}
Verse *GetVerse(int v) const
{
if (v > nVerses || v < 0)
return NULL;
return verse_list[v];
}
};
class Book
{
private:
string book_name;
int pos;
int nChapters;
vector<Chapter*> chapter_list;
public:
Book(const string *buffer, long p);
~Book()
{
}
const string GetBookName() const
{
return book_name;
}
const int GetChapterCount() const
{
return nChapters;
}
const int GetBookPos() const
{
return pos;
}
Chapter *GetChapter(int c) const
{
if (c > nChapters || c < 0)
return NULL;
return chapter_list[c];
}
};
class Bible
{
private:
string title;
string copyright;
vector<Book*> book_list;
int nBooks;
string *buffer;
public:
Bible(const char *fname);
~Bible()
{
}
bool InputFileToMemory(const char *fname);
queue<SearchResult*> *Find(string str);
const string GetTitle() const
{
return title;
}
const string GetCopyright() const
{
return copyright;
}
Book *GetBook(int b) const
{
if (b > nBooks || b < 0)
return NULL;
return book_list[b];
}
const int GetBookCount() const
{
return nBooks;
}
const string GetVerseText(int b, int c, int v) const
{
if (b > nBooks || b < 0)
return string("");
if (c > GetBook(b)->GetChapterCount() || c < 0)
return string("");
if (v > GetBook(b)->GetChapter(c)->GetVerseCount() || v < 0)
return string("");
return GetBook(b)->GetChapter(c)->GetVerse(v)->GetText();
}
};
Chapter::Chapter(const string *buffer, long p)
{
istringstream tmp_buffer;
long verse_pos = 0;
int len = 0;
string verse_text = "";
int i = 0;
// store chapter location incase needed for future reference
pos = p;
nVerses = 0;
// number of verses in chapter
tmp_buffer.str(buffer->substr(p, COUNT_BYTES));
tmp_buffer.read((char*)&nVerses, COUNT_BYTES);
p += COUNT_BYTES;
// set up verses
for (i=0; i<nVerses; i++)
{
// verse location
tmp_buffer.str(buffer->substr(p, LOCATION_BYTES));
tmp_buffer.read((char*)&verse_pos, LOCATION_BYTES);
p += LOCATION_BYTES;
// check that verse has not been left out of Bible. If it has, insert an empty string for the verse text
if (verse_pos > 0)
{
// verse text length
tmp_buffer.str(buffer->substr(verse_pos, LENGTH_BYTES));
tmp_buffer.read((char*)&len, LENGTH_BYTES);
// verse text
verse_text = buffer->substr(verse_pos+LENGTH_BYTES, len);
// insert new book into book list
verse_list.push_back(new Verse(verse_pos, verse_text));
}
else
verse_list.push_back(new Verse(verse_pos, string("")));
}
}
Book::Book(const string *buffer, long p)
{
istringstream tmp_buffer;
long chapter_pos = 0;
int len = 0;
int i = 0;
// store book location incase needed for future reference
pos = p;
nChapters = 0;
book_name = "";
// book name length
tmp_buffer.str(buffer->substr(p, LENGTH_BYTES));
tmp_buffer.read((char*)&len, LENGTH_BYTES);
p += LENGTH_BYTES;
// book name
book_name = buffer->substr(p, len);
p += len;
// number of chapters in book
tmp_buffer.str(buffer->substr(p, COUNT_BYTES));
tmp_buffer.read((char*)&nChapters, COUNT_BYTES);
p += COUNT_BYTES;
// set up chapters
for (i=0; i<nChapters; i++)
{
// chapter location
tmp_buffer.str(buffer->substr(p, LOCATION_BYTES));
tmp_buffer.read((char*)&chapter_pos, LOCATION_BYTES);
p += LOCATION_BYTES;
// insert new book into book list
chapter_list.push_back(new Chapter(buffer, chapter_pos));
}
}
Bible::Bible(const char *fname)
{
istringstream tmp_buffer;
long buffer_offset = 0;
long book_pos = 0;
int len = 0;
int i = 0;
// TODO: better error checking here
if (!InputFileToMemory(fname))
return;
// title length
tmp_buffer.str(buffer->substr(buffer_offset, LENGTH_BYTES));
tmp_buffer.read((char*)&len, LENGTH_BYTES);
buffer_offset += LENGTH_BYTES;
// title
title = buffer->substr(buffer_offset, len);
buffer_offset += len;
// copyright length
tmp_buffer.str(buffer->substr(buffer_offset, LENGTH_BYTES));
tmp_buffer.read((char*)&len, LENGTH_BYTES);
buffer_offset += LENGTH_BYTES;
// copyright
copyright = buffer->substr(buffer_offset, len);
buffer_offset += len;
// number of books
tmp_buffer.str(buffer->substr(buffer_offset, COUNT_BYTES));
tmp_buffer.read((char*)&nBooks, COUNT_BYTES);
buffer_offset += COUNT_BYTES;
// set up books
// get the book locations, then create a new Book object and let do the rest
for (i=0; i<nBooks; i++)
{
// book location
tmp_buffer.str(buffer->substr(buffer_offset, LOCATION_BYTES));
tmp_buffer.read((char*)&book_pos, LOCATION_BYTES);
buffer_offset += LOCATION_BYTES;
// insert new book into book list
book_list.push_back(new Book(buffer, book_pos));
}
delete buffer;
}
// cache bible file in memory for faster access
// return true on success, false on error
bool Bible::InputFileToMemory(const char *fname)
{
fstream in_file;
char *tmp_buffer;
long fsize;
in_file.open(fname, ios::in|ios::binary|ios::ate);
if (in_file == NULL)
return false;
// get size of file
fsize = in_file.tellg();
in_file.seekg(0, ios::beg);
tmp_buffer = new char[fsize];
// read file into buffer
in_file.read(tmp_buffer, fsize);
in_file.close();
buffer = new string(tmp_buffer, fsize);
delete tmp_buffer;
return true;
}
queue<SearchResult*> *Bible::Find(string str)
{
queue<SearchResult*> *results;
int i, j, k;
results = new queue<SearchResult*>;
for (i=0; i<GetBookCount(); i++)
{
for (j=0; j<GetBook(i)->GetChapterCount(); j++)
{
for (k=0; k<GetBook(i)->GetChapter(j)->GetVerseCount(); k++)
{
// check that verse has not been left out of Bible (empty string). If it has, go to the next verse
if (GetVerseText(i, j, k).length() == 0)
continue;
if (GetVerseText(i, j, k).find(str) != -1)
results->push(new SearchResult(i, j, k));
}
}
}
return results;
}
#endif