I write an interpreter, in which each keyword, syntax notation or operator has the base class of Token.
class Token {
private:
static std::vector<Token *> registered;
size_t id;
std::string name;
std::string symbol;
public:
Token(const std::string& Name, const std::string& Symbol);
Token::~Token();
Token(const Token& rhs) = delete;
Token& operator =(const Token& rhs) = delete;
/* ... */
static void DeleteRegistered();
};
The constructor:
Token::Token(const std::string& Name, const std::string& Symbol)
: name(Name), symbol(Symbol) {
Token::registered.push_back(this);
this->id = Token::registered.size();
}
The destructor:
Token::~Token() {
// Removes 'this' from Token::registered
Token::registered.erase(std::remove(Token::registered.begin(), Token::registered.end(), this), Token::registered.end());
}
DeleteRegistered:
void Token::DeleteRegistered() {
for (size_t i = 0; i < Token::registered.size(); ++i) {
delete Token::registered[i];
}
}
In my code, many different classes store containers of pointers to sub-classes which eventually derive from Token.
In order to avoid deleting objects twice or more, I store references to all of the allocated instances, and have a static method which will delete them all.
The method DeleteRegistered is called after all operations are done executing.
Now, to my problem:
When I call Token::DeleteRegistered (which happens a few lines before the program exits, it fails and in debug shows the following:
File: f:\dd\vctools\crt\crtw32\misc\dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Since all of the Token instances don't really have a defined scope, I came up with this design, which to me currently seems OK.
What can cause this error?
EDIT:
The destructor was a late addition of mine, commenting it out still shows the error above. The delete fails to delete even the first item in the container.
2ND EDIT:
An example of how I use Token:
this->parser.Operators.Add(new RefBinaryOperator(
"Assignment", "=", 14, RefBinaryOperator::Assign
));
Note: RefBinaryOperator is a sub-class of Token (Not direct), which eventually calls Token's constructor.
So for instance, I pull pointers to Tokens from the Operators container, and assign them to other structures. When everything is done, I call DeleteRegistered.
FINAL EDIT:
I got it working by declaring the Token destructor as virtual:
Does delete work with pointers to base class?
What is happening is that in Token::~Token() you are calling erase from the registered vector which is invalidating the indices used in the for loop where you noticed the problem. You need to remember that once you call erase on that vector, the for loop indices need to be adjusted properly. If you keep your current destructor the following could work in DeleteRegistered:
void DeleteRegistered() {
while(!Token::registered.empty())
delete *Token::registered.begin();
}
Also, since you have many classes which extend off of Token, ~Token() should become virtual so that the destruction for the base class will be properly handled.
void Token::DeleteRegistered() {
for (size_t i = 0; i < Token::registered.size(); ++i) {
delete Token::registered[i];
}
}
The above will not do what you want. It's going to remove the first (0th) element from registered. What was the second element now becomes the first (0th element), but now i will be 1. Your loop will remove only every other element from Token::registered. It leaks.
One way to handle this: Keep removing either the first or last element while the vector is not empty. I'd suggest deleting the last element because that's more consistent with how vectors work. Deleting the first element until the vector is empty involves rebuilding the vector each step.
void Token::DeleteRegistered() {
while (! Token::registered.empty()) {
delete Token::registered.back();
}
}
Related
Let's assume I got an abstract class ("Book" in the example below) and some derived classes ("ElectroniBook","CodingBook" in the example below). I also want to keep a vector of books in a third class ("Library") and some maps to find them. Let's also assume that I need to create the "Library" from somewhere else using the "addBook" method and then assign it in the main.
Since Book is abstract I eventually need to delete the "Book" pointers I created and I want to do it in some destructor. Neverthless, whenever I try to use delete i got this error message
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
and if I try to replace raw pointers with shared_pointers or unique_pointers I immediately get errors at compile time telling me I'm trying to use pointers that have already been deleted. Note that I'm using C++ 11.
Here's some code just for example :
class Book{
public:
Book(string name, int Npages);
virtual ~Book();
virtual void displayBook() = 0;
private:
string _name;
int _Npages;
}
class ElectronicBook : public Book{
public:
ElectronicBook(string name, int Npages);
~ElectronicBook();
void displayBook() { //do something
};
}
class CodingBook : public Book{
public:
CodingBook(string name, int Npages);
~CodingBook();
void displayBook() { // do something else
};
}
class Library{
public :
Library();
~Library(){
// this doesn't work for me
// for(auto & a : _books)
// delete a;
// _books.clear();
//
//for(int i=0;i<_bookmap.size();++i)
// delete bookmap.at(i);
};
void addCodingBook(string name, int Npages){
CodingBook* cb = new CodingBook(name, Npages);
_books.push_back(cb);
_bookmap[name] = cb;
//should I delete anything here?
};
void addEletronicBook(string name, int Npages){
ElectronicBook* eb = new ElectronicBook(name, Npages);
_books.push_back(eb);
_bookmap[name] = eb;
//should I delete anything here?
};
private :
vector<Book*> _books;
map<string, Book*> bookmap;
}
// separeted function
Library createLibrary(){
Library L;
while(...){
//read books from somewhere(file, input or whatever) and
// addElectronicBook(...)
// addCodingBook(...)
}
return L;
}
int main(){
Library myLibrary = createLibrary();
// do something with Library
}
Since I did several times "new" to add Books, I need to delete them. I tried to do it in the Library destructor like I showed but I got the error mentioned before.
If I understand correctly your issue, you are freeing twice the same memory:
// for(auto & a : _books)
// delete a;
// _books.clear();
//
//for(int i=0;i<_bookmap.size();++i)
// delete bookmap.at(i);
Both _books and bookmap contain pointers that are pointing to the same ares of memory and you are freeing them twice.
When working with raw pointers you have to decide who is the owner of the memory, say, for example _books and who has simply access to the memory but is not responsible for the cleanup.
So, you should:
delete only once, so use only one of the two for loops, say for the sake of argument _books
make sure that the other non-owning structures, say bookmap in our example, never, ever access the memory (i.e. de-reference the pointer) after the deletion
Suggestion: put in the vector unique_ptr so the vector is the owner and put raw pointers in the map to signal that the map is not owning. unique_ptr will take care of cleaning up the memory for you. If you want to be sure, add some print statements or put break points in the destructors if you have a debugger.
I am currently working on implementing something similar to this
(http://molecularmusings.wordpress.com/2011/06/27/config-values/)
while using the template system, so that i do not have to create a class for all types i want to support. Now the class itself works fine, but i am having trouble figuring out how to manage memory if i read config values from a file and save them to the list.
This is my ConfigSetting class:
#pragma once
template <typename T>
class ConfigSetting {
public:
static ConfigSetting* head;
static ConfigSetting* tail;
public:
ConfigSetting(const std::string& name, const std::string& synopsis, T initValue) : m_name(name), m_synopsis(synopsis), m_value(initValue)
{
this->addToList();
}
// Special constructor for int ranges
ConfigSetting(const std::string& name, const std::string& synopsis, T initValue, T minValue, T maxValue) : m_name(name), m_synopsis(synopsis), m_value(initValue), m_min(minValue), m_max(maxValue)
{
this->addToList();
}
ConfigSetting& operator=(T value)
{
this->m_value = value;
return *this;
}
inline operator T(void) const
{
return m_value;
}
static ConfigSetting* findSetting(const std::string& name)
{
if (head) {
ConfigSetting* temp = head;
while (temp != nullptr) {
if (temp->m_name == name) {
return temp;
}
temp = temp->m_next;
}
}
return nullptr;
}
private:
void addToList(void)
{
if (head) {
tail->m_next = this;
tail = this;
}
else {
head = this;
tail = this;
}
}
ConfigSetting* m_next;
const std::string m_name;
const std::string m_synopsis;
T m_value;
T m_min;
T m_max;
};
template<class T> ConfigSetting<T>* ConfigSetting<T>::head = nullptr;
template<class T> ConfigSetting<T>* ConfigSetting<T>::tail = nullptr;
And i am using it like this (from another class called ConfigReader):
ConfigSetting<std::string>* cf = new ConfigSetting<std::string>(key, synopsis, value);
Now my question is: What is the best way manage memory in this case? Since the list is static i cannot just run through the list deleting everything once the destructor gets called. I could be using shared_ptr like this:
shared_ptr<ConfigSetting<std::string>> sp(new ConfigSetting<std::string>(key, synopsis, value));
or another type of smart pointer? Maybe there even is more elegant solution i didn't think of.
As far as I can see, there is nothing in your implicit destructor that must be called to ensure proper operation. If that is true, you can just forget about cleaning up your lists. Trying to do so will only increase the runtime of your program with absolutely no benefit. Just let the kernel do its job, it won't leak any memory pages just because you couldn't be bothered to clean up static data.
However, if you have a nontrivial destructor down the line somewhere which includes such important operations like flushing files or sending messages to other processes, then you must use a destructor function. I'm not talking about the normal C++ destructors here, but about a specially declared function that is executed by the runtime after main() exits.
With gcc, you declare a destructor function like this:
void foo() __attribute__((destructor));
void foo() {
//Do vitally important cleanup here.
}
Since the linker takes care of instructing the runtime to call your destructor function, you do not have to have any call to these functions, they may actually be declared with file local visibility.
Now, you ask "Am I not supposed to delete this pointer somewhere?" Yes, you are supposed to delete it. You are supposed to call delete on every object that you create with new for two reasons:
To give back the memory held by the object to the runtime, so that your process can reuse the memory for other purposes. If you fail to delete objects that you create on a regular basis, the memory footprint of your process will increase indefinitely until the kernel steps in and shoots down your process.
To run the destructor for your object, which frequently results in calling delete on other objects which are not needed anymore. In most cases, this will just give back more memory according to 1., which seems to be your case. It may do more vital operations, though.
Since the objects in question have to live until the very end of your process lifetime (they are static data, after all), you cannot possibly reuse their memory. The kernel, however, is above the level of the runtime that provides you with the new and delete keywords. The kernel is the creator of your tiny process world, in which the new and delete keywords happen to live. The kernel does not care about which parts of the virtual address space your runtime considers used/unused. The kernel will simply strip down the entire virtual address space when your process exits, and the used/unused state of your memory will dissipate into nothingness.
At my university, there is a practical programming test in C++ - and I'm stuck with an example where I am unsure about wheter or not the task in question is even valid and possible to complete correctly.
The (simple) tasks:
Complete the destructor of Person, so that the allocated name is freed again
In the main function, replace //??? with the statement required to free the previously allocated memory
At first, the tasks seemed trivial for me: For the destructor, simply write delete[] name and in the main function, use delete[] friends. Presumably, that is also what the author of this example meant us to do.
However:
There seems to be a flaw in this code example, which causes memory leaks as well as destructors to be called more than once.
The person class has no assignment operator =, meaning that as the existing Person objects such as maria are assigned to slots in the friends array in the main function, the internal allocated names are not copied. So two objects now share the same internal char* pointer! Moreover, the pointer to the name of the Person previously residing in the said array slot is permanentely lost, leading to an unavoidable memory leak.
As delete[] friends; is called - the objects in the array are destroyed - leading to their destructors being called and freeing their name members. When the program ends, though, the local Person objects in the scope of main are destructed - which of course have their name members still pointing to memory which was already freed before.
The actual question:
Is this test example flawed, or am I missing something?
Can the issues listed above be fixed if sticking fully to carrying out the given tasks (altering just the implementation of the destructor, and inserting new code at the commented part in the main function)?
..
#include <iostream>
using namespace std;
int strlen(const char *str) {
if (str==0) return 0;
int i=0;
for (; str[i]; ++i);
return i;
}
void strcpy(const char *src, char *dest) {
if (src==0 || dest==0) return;
int i=0;
for (; src[i]; ++i) dest[i]=src[i];
dest[i]=’\0’;
}
class Person {
char *name;
public:
Person(const char *str = "Susi") {
name = new char[strlen(str)+1];
strcpy(str,name);
}
Person(const Person &p) {
name = new char[strlen(p.name)+1];
strcpy(p.name,name);
}
~Person() {
//...
}
void change() {
name[4]='e';
}
ostream &print(ostream &o) const {
o<<name;
return o;
}
};
int main() {
Person maria("Maria"), peter("Peter"), franz("Franz"), luisa("Luisa");
Person mary(maria);
Person luise;
Person p(luise);
Person *friends= new Person[7];
friends[0]=maria;
friends[1]=peter;
friends[2]=franz;
friends[3]=luisa;
friends[4]=mary;
friends[5]=luise;
friends[6]=p;
friends[5]=luisa;
friends[3].change();
friends[4].change();
for (int i=0; i<7; ++i) {
friends[i].print(cout);
cout<<endl;
}
//???
return 0;
}
You are absolutely right. You can fix it by only making changes at the indicated positions, however they are going to be rather extreme:
Replace the //... inside the destructor with:
delete[] name;
}
Person& operator=(const Person& other)
{
if (this != &other) {
delete[] name; // not completely exception-safe!
name = new char[strlen(other.name)+1];
strcpy(other.name,name);
}
return *this;
Another serious problem is redefining a standard function (strcpy) with a new definition that reorders the arguments.
(See also: SQL injection attacks, which also cause existing pairs of syntax elements, frequently quotes and parentheses, to be re-paired with inserted syntax elements)
Yes, the test example is flawed, possibly it was done consciously. Class Person definitely need assignment operator, remember the Rule Of Three.
No, it's not possible. Default compiler-generated assignment operator will leak memory allocated by objects in friends array and double-delete memory allocated by auto Person objects.
For every new there should be a delete[].
I have a class that holds a few vectors, I'm not sure which method is the best but when the I call the destructor they should be deleted from memory.
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(char* text);
void AddString(string text);
private:
char * StringToCharPointer(string value);
vector<char*> *pVector;
}
CPP File:
Test::Test()
{
};
Test::~Test()
{
vector<char*>::iterator i;
for ( i = pVector->begin() ; i < pVector->end(); i++ )
{
delete * i;
}
delete pVector;
};
char * Test::StringToCharPointer(string value)
{
char *pChar = new char[value.length()];
strcpy(pChar, value.c_str());
return pChar;
};
Test::AddString(char* text)
{
pVector->push_back(text);
};
Test::AddString(string text)
{
pVector->push_back(StringToCharPointer(text));
};
so here's pretty much all the methods that I use, but what's wrong?
Firstly, i is an iterator on the vector, it is not the pointer stored in the vector. *i is the pointer stored in the vector, so if you're going to delete anything it should be that.
Secondly, delete *i is only valid if the object pointed to by *i was allocated with new. Not new[], not malloc, and it doesn't point to a string literal. Since you don't say how your data was allocated, it is not possible for us to say whether or not you are freeing it correctly.
It seems likely that you should use a std::vector<std::string>.
Update for updated question:
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(const string &text);
private:
vector<string> mVector;
};
CPP file:
Test::Test()
{
};
Test::~Test()
{
};
void Test::AddString(const string &text)
{
mVector.push_back(text);
};
Your destruction code looks fine (although I guess you meant delete *i; in the second snippet, since otherwise, ti wouldn't have even compiled.
However, the errors you are getting indicate you put bad things in your vectors. The only char*s that can be inserted in the vector with such destruction code are the ones returned by new char. Especially, you must not insert literals ("abc") or strings that are made as parts of other strings (strtok(NULL, ":"), strchr(str, ':') into it.
This is one obvious problem: char *pChar = new char[value.length()];. You are doing new[] but doing delete in destructor which invoked undefined behavior. You should use delete[] to delete those pointers. But using delete[] might give problems for Test::AddString(char* text) method as you can not be sure how memory for text is allocated i.e. using new or new[] or malloc. The simplest way is to use std::vector<std::string> as suggested by Steve Jossep.
It seems likely that you should use a std::vector<std::string>, to shorten the wise words of Steve Jessop.
To elaborate a little more: you say you want "to make the memory allocation smaller", but sounds like you're at the wrong path if you don't know pointers, and correct me if I'm wrong in guessing premature optimization (usually the case with inexperienced developers in this type of question).
I'm getting an error - heap corruption, can't figure out why.
My base :
h:
class Base
{
public :
Base(char* baseName, char* cityName);
virtual ~Base();
list<Vehicle*>::const_iterator GetEndList();
void PrintAllVehicles(ofstream &ResultFile) const;
char* GetBaseName() const;
char* GetLocation() const;
void InsertNewVehicleToBase(Vehicle* newVehicle);
list<Vehicle*>::const_iterator FindVehicle(char* id);
void RemoveVehicle (list<Vehicle*>::const_iterator beg);
private:
char* m_name;
char* m_location;
list<Vehicle*> m_baseVehicles;
};
cpp :
Base::Base(char* baseName, char* cityName)
{
m_name = new char [strlen(baseName)+1];
strcpy(m_name, baseName);
m_location = new char [strlen(cityName)+1];
strcpy(m_location, cityName);
}
Base::~Base()
{
delete [] m_name;
delete [] m_location;
//m_baseVehicles.clear();
}
army destructor :
Army::~Army()
{
list<Base*>::iterator baseIter = m_basesList.begin();
for (baseIter ; baseIter != m_basesList.end() ; ++baseIter)
delete (*baseIter);
m_basesList.clear();
}
What am I doing wrong?
There's nothing obviously wrong with the code you've shown, so chances are that the error is in code you haven't shown.
The most immediately suspicious thing to me is that the Base class owns two pointers and does not have a copy constructor or assignment operator defined. This means that should you ever copy a Base object, you will end up with two Base objects pointing to the same data, and when they destruct, they will delete it twice, causing heap corruption.
The Army class may also have this problem as well (since it owns several Base pointers), but you don't show the definition of the class, so it's not obvious whether it has a copy constructor and assignment operator or not.
Finally, you haven't shown where the Base objects are being allocated. Is it possible that they are being passed into an Army object and also deleted somewhere outside the Army object? Or perhaps the Base* contained by the Army object are referring to objects on the stack that should not be deleted?
Visible problems with this code:
use of char* not std::string requires manual memory management
Use of
raw pointers in STL containers
overcomplicates cleanup code
use of CRT for string manipulation is
a C++ 'code smell'
Nothing wrong with the piece of code given.
But with this kind of code, there is a high possiblity of mutiple deletion, I mean deletin a memory block twice which leads to heap corruption.
You didn't post the part of the code that has the problem, because all that looks pretty normal. However, it's got a lot of const-correctness problems:
Base(char* baseName, char* cityName);
Strings should be passed as const char* unless they are being modified.
virtual ~Base();
No idea if this needs to be virtual; can't see what its subclasses are.
list<Vehicle*>::const_iterator GetEndList();
Should be a const method, since it's a const_iterator: list<Vehicle*>::const_iterator GetEndList() const;
char* GetBaseName() const;
char* GetLocation() const;
These should return const char*, since your code is not set up to handle the name and location being changed.
list<Vehicle*>::const_iterator FindVehicle(char* id);
Again, should be a const method: list<Vehicle*>::const_iterator FindVehicle(char* id) const;
Base::~Base()
{
delete [] m_name;
delete [] m_location;
//m_baseVehicles.clear();
}
You don't need m_baseVehicles.clear(); because it happens anyway right after the destructor. However, you need to delete the vehicles if they aren't referenced elsewhere, or you'll get a leak.
army distructor :
"destructor". And where is the rest of Army?
Army::~Army()
{
list<Base*>::iterator baseIter = m_basesList.begin();
for (baseIter ; baseIter != m_basesList.end() ; ++baseIter)
delete (*baseIter);
m_basesList.clear();
}
Again, you don't need m_basesList.clear();.
I don't see any problem. Just as Matt Kane said, how does it get populated?
Heap corruptions come from copying more data into an allocated heap cell than the memory allocated to the cell. The beginning and end of heap cells contain data than when overwritten will be reported as a heap corruption.
You have not posted all the code and I cannot see a problem in the code you have posted but I would advise using a memory tool like Valgrind to help you diagnose the problem.