Deallocation of an array of objects? - c++

I'm having some issues deallocating arrays of a class I have. Below is the Class, a simplified implementation and my code I have tried to use to close it.
Characters class
#include <cstdlib>
class Character
{
private:
bool human;
int Xposition; // the character's postion on the board.
int Yposition; // the character's postion on the board.
bool alive;
public:
Character(); //This is my constructor
~Character(); //This is my destructor
bool isHuman(); //return whether type 1 aka Human
bool isZombie(); //return whether type 2 aka Zombie
void setHuman(); //set to type 1 or Human
void setZombie(); //set to type 2 or Zombie
void setPos(int xpos, int ypos); //set the board position
int X();
int Y();
bool isAlive(); //checks to see if a Human is still alive and to be displayed
bool Dead(); //kills the character and sets alive to false
int num_moves_allowed; //number of moves allowed.
};
Allocation code:
Character *characters[11];
int human_count = 0;
for(int i=0; i<12; i++)
{
characters[human_count] = new Character();
human_count++;
}
Termination code:
for(i=11;i<=0;i--)
{
if(characters)
{
characters[i]->~Character();
delete characters[i]; characters[i] = NULL;
}
}
if(characters)
{
//ERROR IS HERE
delete [] characters;
}
I have tried a number of different "delete" commands on the array and I keep getting an "Debug Assertion Failed!" window. It says that the dbgdel.cpp from visual studio vctools is the problem place on Line 52.
It also says "Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Someone please help me I'm sure this is very simple.

I'd suggest you avoid using arrays all together. Use a vector of characters.
Declare your vector as
vector<Character> vCharacters;
then insert objects as
for(int i = 0; i < 100; i++)
vCharacters.push_back(Character());
If you want to store pointers to Character objects then wrap them in a shared_ptr which will take care of deallocating them for you.
vector<shared_ptr<Character>> vCharacters;
for(int i =0; i < 100; i++)
{
shared_ptr<Character> spCharacter(new Character());
vCharacters.push_back(spCharacter);
}
Avoid managing memory yourself when C++ can do it fo ryou

The characters array was allocated on the stack, so you don't have to delete it. However, if you want the array to survive the local scope, create it with something like this:
Character **characters = new Character[11];
then your delete[] line should work fine.
Also note that you don't need to call the destructor of Character explicitly: it is called automatically by delete.

As obelix mentioned, you should use a vector from the Standard Template Library.
However, if you're determined to use a raw array:
const int MAX_CHARACTERS = 11;
Character *characters[MAX_CHARACTERS];
for(int characterCount = 0; characterCount < MAX_CHARACTERS; ++characterCount)
{
characters[characterCount] = new Character();
}
...
if (characters != NULL)
{
for(int i = 0; i < MAX_CHARACTERS; ++i)
{
delete characters[i];
}
}
Paolo Capriotti is correct that characters should be declared with new if you want it to last beyond its scope:
const int MAX_CHARACTERS = 11;
Character **characters = new Character*[MAX_CHARACTERS];
for(int characterCount = 0; characterCount < MAX_CHARACTERS; ++characterCount)
{
characters[characterCount] = new Character();
}
...
if (characters != NULL)
{
for(int i = 0; i < MAX_CHARACTERS; ++i)
{
delete characters[i];
}
delete [] characters;
}
A better solution is the standard vector class:
#include <vector>
...
const int MAX_CHARACTERS = 11;
std::vector<Character> characters;
for (int i = 0; i < MAX_CHARACTERS; ++i)
{
characters.push_back(Character());
}
...
characters.clear();
Notice how much easier the cleanup was? (And in this case, it's optional, since when characters is destroyed it will automatically call the destructor of each item it contains.)

Also:
Character *characters[11];
should be
Character *characters[12];
and
for(i=11;i<=0;i--)
should be
for(i=11;i>=0;i--)

i realize this is a simplified use and all, but why bother with heap access at all?
just using
Character characters[11];
could be just as valid, and safe.
std::vector<> is nice, but if the list is always fixed size, and there's no heap involved in member data, why not?

Related

Dynamically Expanding An Array of Pointers [duplicate]

This question already has answers here:
Initializing a pointer in a separate function in C
(2 answers)
Closed 5 years ago.
I am attempting to build a dictionary using C++.
The dictionary must be dynamically created and updated at all times.
For example, say I have 5 words in my dictionary and I want to add another word, I must create a new dictionary with room for 6 words, copy the old words and add the new word to the new dictionary.
In my main function, I created a lexicon** (pointer to an array of pointers, since each word has a char pointer to it).
I have created a newStr function to receive the new word and to add it to the dictionary and to resort it alphabetically.
The program runs once, but when I want to add another word I get an access violation warning:
0xC0000005: Access violation reading location 0xDDDDDDDD.
I don't understand what I am doing wrong. Thanks for the help!
Here's my code:
#define MAX 80
#include <iostream>
#include <cstring>
#include <string.h>
using namespace std;
void newStr(char** lexicon, int& lexiconSize, char word[])
{
// create the new updated lexicon
char** updated = new char*[++lexiconSize];
// copy the words from the old to the updated lexicon
for (int i = 0; i < lexiconSize; i++)
{
updated[i] = new char[MAX];
if (i < lexiconSize - 1)
{
strcpy_s(updated[i], MAX, lexicon[i]);
}
// add the new word to the end of the updatedLexicon
else
{
strcpy_s(updated[i], MAX, word);
}
}
// deallocate the memory of the worlds of the old lexicon
for (int i = 0; i < lexiconSize - 1; i++)
{
delete[] lexicon[i];
}
// deallocate the memory of the old lexicon
delete[] lexicon;
// point the lexicon pointer to the updatedLexicon
lexicon = updated;
// now sort the lexicon including the new word
if (lexiconSize > 1)
{
for (int i = 1; i < lexiconSize; i++)
{
for (int j = 1; j < lexiconSize; j++)
{
if (strcmp(lexicon[j - 1], lexicon[j]) > 0)
{
char t[MAX];
strcpy_s(t, MAX, lexicon[j - 1]);
strcpy_s(lexicon[j - 1], MAX, lexicon[j]);
strcpy_s(lexicon[j], MAX, t);
}
}
}
}
// deallocate the memory created for the updated lexicon
for (int i = 0; i < lexiconSize; i++)
{
delete[] updated[i];
}
delete[] updated;
return;
}
int main()
{
int lexiconSize = 3;
char** lexicon;
char word[MAX] = {};
// initialize lexicon for testing:
lexicon = new char*[lexiconSize];
lexicon[0] = new char[MAX];
strcpy_s(lexicon[0], MAX, "maybe");
lexicon[1] = new char[MAX];
strcpy_s(lexicon[1], MAX, "this");
lexicon[2] = new char[MAX];
strcpy_s(lexicon[2], MAX, "works");
cout << "enter the word to add" << endl;
cin >> word;
newStr(lexicon, lexiconSize, word);
// menu system that allows to add/delete/print the words
// delete the lexicon at the end of the program
for (int i = 0; i < lexiconSize; i++)
{ // delete the internal words
if (lexicon[i])
{
delete[] lexicon[i];
}
}
if (lexicon)
{
delete[] lexicon;
}
return 0;
}
Your problem is that lexicon is passed to newStr() by value.
The assignment lexicon = updated is therefore not visible to the caller.
Since the function releases all dynamically allocated memory referenced by lexicon[i], all subsequent uses of lexicon in main() therefore have undefined behaviour.
Incidentally, all the memory allocated inside newStr() is leaked - no variable refers to it after the function returns, so it cannot be released in code.
Instead of trying to use pointers and operator new directly, look up standard containers (std::vector) and std::string (to manage string data).
This is not a C++ code: it's C with some bit of syntax sugar.
Do not deallocate something inside function, if you have created it
in another place.
Use smart pointers.
Do you really think, that your implementation will be more effective
and potable, than std::vector/std::map?

Dealing with accessing NULL pointer

In my class, I've got - inter alia - a pointer:
Class GSM
{
//...
private:
char *Pin;
//...
}
My constructor initialize it as:
GSM::GSM()
{
//...
Pin = NULL;
//...
}
Now, I want to set default value ("1234") to my PIN. I tried very simple way:
bool GSM::setDefaultValue()
{
lock();
Pin = "0";
for (uint8 i =0; i < 4; ++i)
{
Pin[i] = i+1;
}
unlock();
return true;
}
But it didn't work. When I run my program (I use Visual Studio 2010) there is an error:
Access violation writing location 0x005011d8
I tried to remove line
Pin = "0";
But it didn't help. I have to initialize it as NULL in constructor. It's part of a larger project, but I think, the code above is what makes me trouble. I'm still pretty new in C++/OOP and sometimes I still get confused by pointers.
What should I do to improve my code and the way I think?
EDIT: As requested, I have to add that I can't use std::string. I'm trainee at company, project is pretty big (like thousands of files) and I did not see any std here and I'm not allowed to use it.
You need to give the Pin some memory. Something like this:
Pin = new char[5]; // To make space for terminating `\0`;
for(...)
{
Pin[i] = '0' + i + 1;
}
Pin[4] = '\0'; // End of the string so we can use it as a string.
...
You should then use delete [] Pin; somewhere too (Typically in the destructor of the class, but depending on how it's used, it may be needed elsewhere, such as assignment operator, and you need to also write a copy-constructor, see Rule Of Three).
In proper C++, you should use std::string instead, and you could then do:
Class GSM
{
//...
private:
std::string Pin;
....
Pin = "0000";
for (uint8 i =0; i < 4; ++i)
{
Pin[i] += i+1;
}
Using std::string avoids most of the problems of allocating/deallocating memory, and "just works" when you copy, assign or destroy the class - because the std::string implementation and the compiler does the work for you.
You need to allocate a block of memory to store "1234". This memory block will be pointed by your Pin pointer.
You can try:
bool GSM::setDefaultValue()
{
lock();
Pin = new char[4];
for (uint8 i =0; i < 4; ++i)
{
Pin[i] = '0' + (i + 1);
}
unlock();
return true;
}
As you have allocated dynamicaly a memory block, you should always release it when you don't need it anymore. To do so, you should add a destructor to your class:
GSM::~GSM()
{
delete [] Pin;
}
Simple answer:
Instead of using the heap (new delete) just allocate space in your class for the four character pin:
Class GSM
{
//...
private:
char Pin[5];
//...
}
The length is fixed at 5 (to allow space for 4 characters and terminating null ('\0'), but as long as you only need to store a maximum of 4 characters, you are fine.
Of course, if you want to make it easy to change in the future:
Class GSM
{
//...
private:
const int pin_length = 4;
char Pin[pin_length+1];
//...
}
Your function to set the value will then look like:
bool GSM::setDefaultValue()
{
lock();
for (char i = 0; i < pin_length; ++i)
{
Pin[i] = i+1;
}
Pin[pin_length]=0;
unlock();
return true;
}
or even:
bool GSM::setDefaultValue()
{
lock();
strcpy(Pin,"1234"); //though you would have to change this if the pin-length changes.
unlock();
return true;
}

2D Array of Pointers -> Classes

I am having problems with my constructor in class World.
I created a 2D array with pointers where each entry in the array is of type Organism, hence the line of code:
Organism* grid[20][20];
When I run my program, I only see
hello
and after that, I get a message saying that my program has stopped working. I'm pretty sure it's the line of code
grid[i][j]->symbol = ' ';
that's causing the problem. Just to see what would happen, I changed that line to
grid[i][j];
and didn't get any errors. But, the moment I put ->, I seem to get errors.
Is there a reason why my program stops working after I put ->? Any help would be appreciated.
This is my code:
#include <iostream>
using namespace std;
class Organism
{
public:
char symbol;
};
class World
{
public:
World();
private:
Organism* grid[20][20];
};
int main()
{
World world;
return 0;
}
World::World()
{
for(int i = 0; i < 20; i++)
for(int j = 0; j < 20; j++)
{
cout << "hello" << endl;
grid[i][j]->symbol = ' ';
cout << "here" << endl;
}
}
You have an array of pointers to Organism.
Pointers can not hold any data other than an address. They can only point to memory (that holds data).
Your array's pointers does not point to anything, thats why you get undefined behaviour when you try to assign data to where the pointers point at.
You need to allocate memory for your array.
Organism grid[20][20]; // Create an array of objects (not pointers).
/* ... */
grid[i][j].symbol = ' ';
Same using dynamic memory:
class World {
public:
World();
~World(); // Rule of Three.
World(const World&) = delete; // Rule of Three.
World& operator=(const World&) = delete; // Rule of Three.
private:
Organism** grid;
};
World::World() {
grid = new Organism*[20]; // Allocate memory to point to.
for(std::size_t i = 0; i != 20; ++i) {
grid[i] = new Organism[20]; // Allocate memory to point to.
for(std::size_t j = 0; j != 20; ++j) {
cout << "hello" << endl;
grid[i][j].symbol = ' ';
cout << "here" << endl;
}
}
}
// Destructor needed to deallocate memory (otherwise it will leak).
World::~World()
{
for (std::size_t i = 0; i != 20; ++i) {
delete[] grid[i];
}
delete[] grid;
}
Now you can see how complicated it gets when using dynamic memory and why it's recommended to prefer to use automatic storage duration (i.e. create objects, not pointers and new/delete).
Even better is to use a container from the standard library for storing your elements as e.g. std::vector.
Related:
What is The Rule of Three?
Change
Organism* grid[20][20];
To
Organism grid[20][20];
and use
grid[i][j].symbol = '';
instead of
grid[i][j]->symbol = '';
and add a default constructor to Organism
class Organism
{
Organism();
...
}
or make Organism a struct
struct Oranism
{
...
}

Memory leaks from 2d array on heap

I'm having an issue with a lot of memory leaks from a class I've created. The assignment is requires creating a word search puzzle on the heap. I've created my destructor, copy constructor and overload the assignment operator.
I think there must be something wrong with one of these functions, because the final check to ensure it is working is to create objects in a loop, to see if it fails and my function is crashing. I've tried different forms of the destructor and I've tried changing around the copy and assignment operator with no luck. Kind of at a loss, and the lack of warnings is really making it difficult to debug without a proper understanding of the heap.
Any help would be really appreciated!
Here are some functions that are working with the heap.
JumblePuzzle::~JumblePuzzle(){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete jumble;
}
JumblePuzzle::JumblePuzzle(string word, string diff){
int i = 0;
toHide = word;
difficulty = diff;
jumble = buildArray();
fillArray();
hideWord();
}
JumblePuzzle::JumblePuzzle(JumblePuzzle& temp){
size = temp.size;
rowPos = temp.rowPos;
colPos = temp.colPos;
direction = temp.direction;
toHide = temp.toHide;
difficulty = temp.difficulty;
jumble = temp.getJumble();
}
JumblePuzzle& JumblePuzzle::operator=(const JumblePuzzle& right){
if (this != &right){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete[] jumble;
size = right.size;
rowPos = right.rowPos;
colPos = right.colPos;
direction = right.direction;
toHide = right.toHide;
difficulty = right.difficulty;
jumble = right.getJumble();
}
return *this;
}
charArrayPtr* JumblePuzzle::buildArray() const{
charArrayPtr* array = new char*[size];
for (int i = 0; i < size; ++i){
array[i] = new char[size];
}
return array;
}
Here's the line its failing on.
int loopLimit =20;
for (int i = 0; i < loopLimit; i++)
JumblePuzzle jp("HIDDENWORD", "hard");
Thanks for any possible help!
EDIT:
Here is my .h file as well.
#ifndef JUMBLE_H_
#define JUMBLE_H_
#include <time.h>
#include <cstdlib>
#include <string>
using namespace std;
typedef char* charArrayPtr;
class BadJumbleException {
public:
BadJumbleException(const string&);
string& what();
private:
string message;
};
class JumblePuzzle{
public:
JumblePuzzle(string, string); //simple constructor
JumblePuzzle(JumblePuzzle&); //copy constructor
~JumblePuzzle(); //deconstructor
charArrayPtr* getJumble() const;
JumblePuzzle& operator=(const JumblePuzzle&);
//accessors
int getSize();
int getRowPos();
int getColPos();
char getDirection();
private:
//attributes
int size;
int rowPos;
int colPos;
char direction;
charArrayPtr* jumble;
string toHide;
string difficulty;
void fillArray();
void hideWord();
char randomDirection();
int randomNum(int);
charArrayPtr* buildArray() const;
};
#endif
and my getJumble. It's used to get the actual word search created. Returned a copy rather than the pointer so it cant be modified.
charArrayPtr* JumblePuzzle::getJumble() const{
charArrayPtr* tempJumble = new char*[size];
for (int i = 0; i < size; ++i){
tempJumble[i] = new char[size];
}
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
tempJumble[i][j] = jumble[i][j];
}
}
return tempJumble;
}
There is one major thing wrong with your code, and that is you failed to initialize the "size" member in the JumblePuzzle(string, string) constructor.
There are other things you should do:
1) Create a separate function to destroy the 2d array within the JumblePuzzle class. You seem to be copying the same loops to do this in multiple places. No need for that if you just call a function to do this work.
2) Your assignment and copy constructor are not exception safe. If new[] throws an exception during the creation of the copy, then the original object has invalidated data. In other words, you've destroyed the data, and when you want to create another 2d array, when new[] says "oops", you've destroyed your original data and can't get it back.

c++ and xcode - calling objects function throws EXC_BAD_ACCESS

This code works fine in VS2010 but now I am trying to port it to my mac with xcode 4.6 and it's giving me some bad access errors at run time. Basically I have a board class which contains a 2d array of tiles, when I create the board I can access the tiles functions but when I later run my draw function it gives me bad access. Here is a sample of my board class.
Board.h
#include "Tile.h"
class Board
{
private:
//This is the GameBoard of a 2D array of Tiles
Tile *** GameBoard;
void CreateBoard(const int size);
void FillValues();
...
public:
Board(int size);
void DrawBoard();
...
}
Board.cpp
Board::Board(const int size)
{
won=false;
lost=false;
BoardSize =size;
GameBoard = new Tile**[size];
CreateBoard(size);
}
void Board::CreateBoard(const int size)
{
...
FillValues()
}
void Board::FillValues()
{
for(int x=1;x<BoardSize+1;x++)
{
for(int y =1;y<BoardSize+1;y++)
{
if (GameBoard[x][y]->Type()=="NumberTile")
{
int neighbors = CountNeighbours(x,y);
GameBoard[x][y]->SetValue(neighbors);
//This works
}
}
}
}
void Board::DrawBoard()
{
for(int i=0;i<=BoardSize+1;i++)
{
for (int j=0;j<=BoardSize+1;j++)
{
if (GameBoard[i][j]->Type() != "BorderTile") {
GameBoard[i][j]->Draw();
//This does not work, i get the error when it tries to use ->Type()
}
}
}
}
...
I call the functions like this
GI = new Board(SCREEN_SIZE);
GI->DrawBoard();
GameBoard = new Tile**[size];
This just creates an array of Tile**. You don't yet have any actual Tiles or even Tile*s and later, when you're trying to access elements of the array with GameBoard[x][y]->, you're hitting undefined behaviour.
As you have it, you would need to do this:
GameBoard = new Tile**[size]; // Allocate an array of Tile**
for (int i = 0; i < size; i++) {
GameBoard[i] = new Tile*[size]; // Allocate an array of Tile*
for (int j = 0; i < size; j++) {
GameBoard[i][j] = new Tile(); // Allocate an array of Tile
}
}
However, this is awful. It's three lots of dynamic allocation that you have to remember to tidy up at the end (and tidy up correctly).
A simpler approach would be to just have an 2D array of tiles:
Tile GameBoard[CONSTEXPR_SIZE][CONSTEXPR_SIZE];
Or better yet, use the std::array container:
std::array<std::array<Tile, CONSTEXPR_SIZE>, CONSTEXPR_SIZE> GameBoard;
Here, the size given has to be a constant expression. If you need it to be dynamically sized, use a std::vector instead.
In the comments below, you say the size of your array is actually BoardSize+1. Still, you are iterating over too many elements in both your outer and inner for loops:
for(int i=0;i<=BoardSize+1;i++)
This should be:
for(int i=0; i<BoardSize+1; i++)
Also in the comments below, you say that Type returns a char*. That means you can't do your string comparison like this:
GameBoard[i][j]->Type() != "BorderTile"
This simply performs pointer comparison, since the left operand is a char* and the right operand is convertible to const char*. It doesn't compare the strings themselves. Instead, you want:
GameBoard[i][j]->Type() != std::string("BorderTile")
This will force std::string comparison to be used.