I'm sure this has been asked before, but the search terms are failing me for my specific situation.
Essentially, I'm creating a 2D tile engine. For overall efficiency and to reduce a bit of overhead, I have decided to implement my own simple memory management container...
The following code is what I'm using to do so:
Tile.h:
//Tile class
class CTile
{
public:
CTile();
~CTile();
unsigned int row;
unsigned int column;
};
//Container class
class CTileLayer
{
public:
CTileLayer(unsigned int nRows, unsigned int nCols, float w, float h);
~CTileLayer();
protected:
CTile** m_tiles;
unsigned long count;
void Allocate(unsigned int nRows, unsigned int nCols, float w, float h);
void Free();
};
Tile.cpp:
#include "Tile.h"
CTile::CTile() : row(0), column(0)
{
}
CTile::~CTile()
{
}
CTileLayer::CTileLayer(unsigned int nRows, unsigned int nCols, float w, float h) : m_tiles(NULL)
{
Allocate(nRows, nCols, w, h);
}
CTileLayer::~CTileLayer()
{
if(m_tiles != NULL) Free();
}
void CTileLayer::Allocate(unsigned int nRows, unsigned int nCols, float w, float h)
{
unsigned int column = 0, row = 0;
if(m_tiles != NULL) Free();
m_tiles = new CTile*[count = (nRows * nCols)];
for( unsigned long l = 0; l < count; l++ ) {
m_tiles[l] = new CTile[count];
m_tiles[l]->column = column + 1;
m_tiles[l]->row = row + 1;
//
//...
//
if(++column > nCols) {
column = 0;
row++;
}
}
}
void CTileLayer::Free()
{
delete [] *m_tiles;
delete [] m_tiles;
m_tiles = NULL;
count = 0;
}
So by seeing how each tile is allocated/freed, is it safe to say this won't produce any memory leaks?
If it will, what would be the most appropriate way to free this array, while making sure each object's destructor gets called? Should I loop through the array, manually deleting each object instead?
Why not do this:
CTile* m_tiles;
m_tiles = new CTile[nRows*nColumns];
delete[] m_tiles;
You called new CTile[count] count times, once for each m_tiles[l].
You need to therefore call delete[] count times, for each m_tiles[l].
It isn't clear what count is good for, however. You should be using nRows and nColumns for the two layers of the array. Right now you have nRows * nRows * nColumns * nColumns instances of CTile allocated, which is probably too many.
Instead try
m_tiles = new CTile*[nRows];
m_tiles[l] = new CTile[nColumns];
Related
I'm designing a dynamic hurtbox for characters in a text-based game, which catches the locations of hits (or misses) of a weapon swung at them. The location (indices) and damage (magnitude) of hits are then translated into decreases in corresponding limb health variables for a character. My thoughts are that this hurtbox would best be implemented using a class with some 3D vector/array member.
Naturally, I might want varying dimensions of the 3D container for different sizes of enemy, but I'm aware that size is usually determined upon initialization. So here's my question:
Would it be more efficient to use a C-style dynamic array, the size of which I can decide and allocate inside a parameterized constructor, like so?
class hurtBox {
private:
int ***hurtBoxMatrix;
public:
hurtBox(int l, int w, int h) {
hurtBoxMatrix = new int**[l];
for (int i = 0; i < l; i++) {
hurtBoxMatrix[i] = new int*[w];
for (int j = 0; j < w; j++) {
hurtBoxMatrix[i][j] = new int[h] ();
}
}
}
};
Or, would a vector that I push elements into, up to my desired dimensions, suffice?
class hurtBox {
private:
vector<vector<vector<int>>> hurtBoxMatrix;
public:
hurtBox(int l, int w, int h) {
for (int i = 0; i < l; i++) {
hurtBoxMatrix.push_back(vector<vector<int>>);
for (int j = 0; j < w; j++) {
hurtBoxMatrix[i].push_back(vector<int>);
for (int k = 0; k < h; k++) {
hurtBoxMatrix[i][j].push_back(0);
}
}
}
}
};
I imagine the former, since that first allocation is constant time, right? Is there a way to do this that's better than either of these?
Thanks in advance.
You'd be better off simply allocating the 3D array in a single allocation, and use indexing to access the elements. Allocation for the std::vector storage can then be handled in the constructor for std::vector.
In general it's best to avoid:
multiple allocations
repeatedly calling push_back
class hurtBox {
private:
vector<int> hurtBoxMatrix;
int m_l;
int m_w;
int m_h;
public:
hurtBox(int l, int w, int h)
: hurtBoxMatrix(l * w * h), m_l(l), m_w(w), m_h(h) {}
int& operator (int i, int j, int k) {
return hurtBoxMatrix[ I*m_w*m_h + j*m_w + k ];
}
const int operator (int i, int j, int k) const {
return hurtBoxMatrix[ i*m_w*m_h + j*m_w + k ];
}
};
I took a programming class at university this semester, just out of curiosity. We're doing C++ and I enjoyed it a lot, but the last two weeks have been rather steep for me and heres what troubles my mind:
I'm given a class interface as follows:
class GameOfLife(int rows, int cols);
public:
GameOfLife();
void clear();
void set(int row, int col, int value);
void set(int row, int col, const char* values);
int get(int row, int col);
void print();
void advance();
};
First thing im being asked to do is to implement the constructor so that it allocates memory for a board with the amount of rows and cols passed in the argument. I thought i understood constructors but with this one I'm pretty lost.
After i declared int rows and cols in the private section i thought about something along the lines of
GameOfLife::GameOfLife(int x, int y){
rows = x;
cols = y;
board = new int* [rows];
But neither do i know how to handle the second dimension of the board without the compiler yelling at me nor do i know how to test if new memory is actually allocated properly.
Any help? :(
Thanks in advance!
In addition to thumbmunkey's correct answer, note that just because the external interface stipulates a 2D array doesn't mean the internal interface has to match.
You could have:
int* board = new int[rows * cols];
Where then instead of get() returning:
return board[x][y];
it would instead be:
return board[x * rows + y];
Sometimes one array is easier to think about than two. Sometimes it's not. Depends on how you want to do it (or if it's stipulated that you have to use one method or the other).
You have to allocate the column array for each row:
for(int i=0; i<rows; i++)
board[i] = new int [cols];
If the allocation fails (eg. when you're out of memory), you will get an exception.
What you are doing right now with board = new int* [rows];
Is allocating an array of integer pointers. You still need to allocate the memory for the actual integers which is what thumbmunkey is doing with,
for(int i=0;i<rows;i++)
board[i] = new int [cols];
There is already a class to dynamically manage memory, it's called vector. If you try to use new in your code then you end up having to reinvent the wheel and write dozens of lines of boilerplate that already exists inside vector.
Also it is simpler to store your board in a contiguous array, there is no need to use a bunch of separate memory blocks to hold the board.
Here is an example:
class GameOfLife
{
public:
GameOfLife(int rows, int cols);
void clear();
void set(int row, int col, int value);
void set(int row, int col, const char* values);
int get(int row, int col);
void print();
void advance();
private:
int rows, cols;
std::vector<int> values;
};
// In the cpp file
GameOfLife::GameOfLife(int rows, int cols)
: rows(rows), cols(cols), values(rows * cols) {}
void GameOfLife::set(int row, int col, int value)
{ values.at(row * cols + col) = value; }
int GameOfLife::get(int row, int col)
{ return values.at(row * cols + col); }
The essentials - constructor, destructor, getters:
class GameOfLife
{
public:
GameOfLife(int _rows, int _cols);
~GameOfLife ();
int GetRows () {return rows;}
int GetCols () {return cols;}
int **GetBoard () {return board;}
private:
int rows, cols;
int **board;
};
GameOfLife::GameOfLife(int _rows, int _cols)
{
rows = _rows;
cols = _cols;
board = new int *[rows];
for (int i = 0; i<rows; i++)
board[i] = new int[cols];
}
GameOfLife::~GameOfLife()
{
for (int i = 0; i<rows; i++)
delete [] board[i];
delete [] board;
}
I want to work with Images, and I want to create my structure Image with first 2 values to be it's size (grayscale) and the third - data (2D array of size m by n).
How can I implement it? If I don't know the image's size in advance. Something like this:
struct Image{
int n;
int m;
data = 2D array of size mxn
}
Instead I would use
struct Image{
int n;
int m;
vector<vector<int>> data;
}
Of you could use a 1D vector that has size
vector<int> data(m * n);
Ignoring encapsulation, something like this could work:
#include <vector>
struct Image {
int n;
int m;
std::vector<std::vector<int>> data; // May want to change int type ?
Image(int n, int m) : n(n), m(m), data(n) {
for (int row = 0; row < n; row++) {
data[row].resize(m);
}
}
};
// Example Usage
Image img(10, 10);
for (int row = 0; row < img.n; row++) {
for (int col = 0; col < img.m; col++) {
img.data[row][col] = valueFromImageFile;
}
}
If you're not just looking for something quick and dirty, and this is going to be an ongoing project, I would recommend that you learn more about object oriented concepts :)
There are two common patterns for that (even if inherited from C). Both share a common principle : a logical separation between a fixed size header and a variable part.
First method : the struct contains the fixed size part and a pointer (or pointers in a generic case) to memory allocated with new (in constructor) and deallocated in destructor. It is a bit hand-driven, but easy to use and to understand.
Image could look like (I assume Pixel is a class representing a single pixel):
class Image {
private:
int _x, _y;
Pixel *data;
public:
Image(int x, int y);
~Image();
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image::Image(int x, int y) {
data = new Pixel[x * y];
_x = x;
_y = y;
}
Image::~Image() {
delete[] data;
data = NULL;
}
Second method : the pseudo-struct is composed of a fixed size header, and of a dynamic part. The dynamic part is declared in the struct to be of size 1. It is obviously false, and you cannot use sizeof on such a struct, but as C does not inforce comparison of array to the declared size it works :
class Image {
private:
int _x, _y;
Pixel data[1];
Image(int x, int y); // private to force usage of createImage
public:
static Image* createImage(int x, int y);
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image* Image::createImage(int x, int y) {
Image* image = (Image *) malloc(sizeof(Image) + (x * y - 1) * sizeof(Pixel));
image->_x = x;
image->_y = y;
return image;
}
I must admit it is really C code embedded in C++, but I cited it because it is heavily used in Microsoft Win32 API.
For a vector in C++, I have
class Vec
{
public:
int len;
double * vdata;
Vec();
Vec(Vec const & v)
{
cout<<"Vec copy constructor\n";
len = v.len;
vdata=new double[len];
for (int i=0;i<len;i++) vdata[i]=v.vdata[i];
};
I would greatly appreciate it if you could help me how to write an analogous code for a matrix. I am thinking something like this:
class Mat
{
public:
int nrows;
int ncols;
double * mdata;
Mat();
Mat(Mat const & m)
{
cout<<"Mat copy constructor\n";
nrows = m.nrows;
ncols = m.ncols;
But I don't know how to code the memory allocation for a matrix using the idea that first we put all the elements into a 1D array (row1 row2 ... rown) then we chop the array into rows and then chop each row into columns. Particularly, could you help me translate this idea into C++ language that is analogous to the following:
vdata=new double[len];
for (int i=0;i<len;i++) vdata[i]=v.vdata[i];
};
I am thinking of something like this:
double *data=new double[nrows*ncols];
for (int i=0;i<nrows;i++)
{
for (int j=0;j<ncols,j++){data(i,j)=m.mdata[i][j]};
};
But I am not sure about this part:
data(i,j)=m.mdata[i][j]
Also, I am supposed to use a pure virtual element indexing method: the (i,j) element of a Mat object m will be retrieved by m(i,j). I have to provide both const and non-const versions of this indexing operator.<-- May you show me how I could do this?
Thanks a lot.
Use as a single-dimensional array. You will notice that in practice, it's generally much simpler to use a 1d-array for such things.
class Matrix
{
public:
Matrix(unsigned int rows, unsigned int cols)
: _rows(rows)
, _cols(cols)
, _size(_rows*_cols)
, _components(new double[_size])
{
for(unsigned int i = 0; i < _size; ++i)
{
_components[i] = 0;
}
}
~Matrix()
{
delete[] _components;
}
double& operator()(unsigned int row, unsigned int col)
{
unsigned int index = row * _cols + col;
return _components[index];
}
private:
unsigned int _rows;
unsigned int _cols;
unsigned int _size;
double* _components;
};
However, if you want to actually use matrices and vectors, and not just implement them for learning, I would really advise you to use the Eigen library. It's free and open source and has great and easy-to-use vector and matrix classes.
While Eigen is great to use, if you want to look at source code of an existing implementation, it can be quite confusing for new programmers - it's very general and contains a lot of optimizations. A less complicated implementation of basic matrix and vector classes can be found in vmmlib.
Also you can use one standard vector to implement matrix but vector size will be nrows * ncols:
#include <vector>
class Mat {
public:
Mat(int rows, int cols):
nrows(rows),
ncols(cols),
elems(rows*cols,0)
{}
Mat(const Mat &m):
nrows(m.nrows),
ncols(m.ncols),
elems(m.elems.begin(), m.elems.end())
{}
double celem(int i,int j) const {
return elems[ncols*i + nrows*j];
}
double *pelem(int i,int j) {
return &elems[ncols*i + nrows*j];
}
private:
int nrows;
int ncols;
vector<double> elems;
};
Is there some way to delay defining the size of an array until a class method or constructor?
What I'm thinking of might look something like this, which (of course) doesn't work:
class Test
{
private:
int _array[][];
public:
Test::Test(int width, int height);
};
Test::Test(int width, int height)
{
_array[width][height];
}
What Daniel is talking about is that you will need to allocate memory for your array dynamically when your Test (width, height) method is called.
You would declare your two dimensional like this (assuming array of integers):
int ** _array;
And then in your Test method you would need to first allocate the array of pointers, and then for each pointer allocate an array of integers:
_array = new *int [height];
for (int i = 0; i < height; i++)
{
_array [i] = new int[width];
}
And then when the object is released you will need to explicit delete the memory you allocated.
for (int i = 0; i < height; i++)
{
delete [] _array[i];
_array [i] = NULL;
}
delete [] _array;
_array = NULL;
vector is your best friend
class Test
{
private:
vector<vector<int> > _array;
public:
Test(int width, int height) :
_array(width,vector<int>(height,0))
{
}
};
I think it is time for you to look up the new/delete operators.
Seeing as this is a multidimensional array, you're going to have to loop through calling 'new' as you go (and again not to forget: delete).
Although I am sure many will suggest to use a one-dimensional array with width*height elements.
(Months later) one can use templates, like this:
// array2.c
// http://www.boost.org/doc/libs/1_39_0/libs/multi_array/doc/user.html
// is professional, this just shows the principle
#include <assert.h>
template<int M, int N>
class Array2 {
public:
int a[M][N]; // vla, var-len array, on the stack -- works in gcc, C99, but not all
int* operator[] ( int j )
{
assert( 0 <= j && j < M );
return a[j];
}
};
int main( int argc, char* argv[] )
{
Array2<10, 20> a;
for( int j = 0; j < 10; j ++ )
for( int k = 0; k < 20; k ++ )
a[j][k] = 0;
int* failassert = a[10];
}