I have a simple ball class. It takes a color name for its initialization.
Ball::Ball(ColorName color_name) : m_color_name{color_name} {
}
I try to create a 2d-vector board to contain some balls. The width and the height are given outside.
class Board {
private:
int m_width;
int m_height;
std::vector<std::vector<Ball>> m_grids;
public:
Board(int width, int height);
~Board();
};
Board::Board(int width, int height) : m_width{width}, m_height{height} {
m_grids.resize(height);
for (int row_num = 0; row_num < height; row_num ++) {
m_grids[row_num].resize(width);
}
}
Then the compiler complains that the ball class needs default constructor for resizing.
Then I try to change it to pointer.
class Board {
private:
int m_width;
int m_height;
std::vector<std::vector<Ball> *> *m_grids;
public:
Board(int width, int height);
~Board();
};
Board::Board(int width, int height) : m_width{width}, m_height{height} {
m_grids->resize(height);
for (int row_num = 0; row_num < height; row_num ++) {
m_grids->at(row_num)->resize(width);
}
}
Or
Board::Board(int width, int height) : m_width{width}, m_height{height} {
m_grids->resize(height, new std::vector<Ball>[width]);
for (int row_num = 0; row_num < height; row_num ++) {
m_grids->at(row_num)->resize(width);
}
}
They still complain the same thing.
So far I can only create the default constructor for workaround.
Ball::Ball() {
m_color_name = ColorName::Default;
}
But I really don't like it because the balls should not be "default_color". Thy should be like "yellow", "pink" or some color I defined elsewhere.
Is there a way to avoid creating that constructor?
Well, if you don't know what color the balls on a new empty board should be, C++ cannot help you with it. You did not provide a default constructor for the type, so C++ has no way of knowing which default value to use. You have several options here.
One. Use board of std::optional<ColorName>. In this case, you will have an explicit "default" state which is std::nullopt. However, you would need to be careful and always make sure the color is emplaced if you need it.
Two. Do not create the board beforehand. Create it only when you know what color should be there. E.g. it is ok to do m_grids[row_num].push_back(ColorName::Whatever);, you don't need a default constructor for that.
As for pointers (be it raw or smart) - forget it. You don't need pointers in this task.
Instead of making the vectors to pointers (which doesn't make any sense), the entries themselves should be pointers. Since pointers can be nullptr, the vectors will be resizable, like this:
std::vector<std::vector<Ball *>> m_grids_bad;
// Or even better:
std::vector<std::vector<std::unique_ptr<Ball>>> m_grids;
// You can then assign things like this (for example):
m_grids[4][5] = std::make_unique<Ball>(ColorName::RED, 5);
I would strongly recommend you always use std::unique_ptr where possible, or std::shared_ptr, since nothing speaks against it. It helps you with freeing memory when exceptions are thrown, or allows you to share ownership of some memory address, etc. Just do it.
Resizing the vectors will now work like you want to, because std::unique_ptr has a default constructor which just initializes its internal pointer to nullptr.
PS: Maybe I should elaborate on why storing vectors on the heap doesn't make sense. Vectors already can store their content on the heap, and dynamically reallocate memory when required.
Another thing: Vectors to pointers are also really useful if your element type is unmovable. This could come in handy in multithreading situations, where threads sometimes are initialized with a pointer to something, and rely on that something to stay exactly where it is in memory.
Related
I went to a job interview today and was given this interesting question.
Besides the memory leak and the fact there is no virtual dtor, why does this code crash?
#include <iostream>
//besides the obvious mem leak, why does this code crash?
class Shape
{
public:
virtual void draw() const = 0;
};
class Circle : public Shape
{
public:
virtual void draw() const { }
int radius;
};
class Rectangle : public Shape
{
public:
virtual void draw() const { }
int height;
int width;
};
int main()
{
Shape * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i)
shapes[i].draw();
}
You cannot index like that. You have allocated an array of Rectangles and stored a pointer to the first in shapes. When you do shapes[1] you're dereferencing (shapes + 1). This will not give you a pointer to the next Rectangle, but a pointer to what would be the next Shape in a presumed array of Shape. Of course, this is undefined behaviour. In your case, you're being lucky and getting a crash.
Using a pointer to Rectangle makes the indexing work correctly.
int main()
{
Rectangle * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i) shapes[i].draw();
}
If you want to have different kinds of Shapes in the array and use them polymorphically you need an array of pointers to Shape.
As Martinho Fernandes said, the indexing is wrong. If you wanted instead to store an array of Shapes, you would have to do so using an array of Shape *'s, like so:
int main()
{
Shape ** shapes = new Shape*[10];
for (int i = 0; i < 10; ++i) shapes[i] = new Rectangle;
for (int i = 0; i < 10; ++i) shapes[i]->draw();
}
Note that you have to do an extra step of initializing the Rectangle, since initializing the array only sets up the pointers, and not the objects themselves.
When indexing a pointer, the compiler will add the appropriate amount based on the size of what's located inside the array. So say that sizeof(Shape) = 4 (as it has no member variables). But sizeof(Rectangle) = 12 (exact numbers are likely wrong).
So when you index starting at say... 0x0 for the first element, then when you try to access the 10th element you're trying to go to an invalid address or a location that's not the beginning of the object.
class tile :public RectangleShape
{
public:
int w;
int t1rgb1;
int t1rgb2;
int t1rgb3;
int t2rgb1;
int t2rgb2;
int t2rgb3;
void modify(int,int,int,int,int,int,int);
};
I have a tile class that inherits RectangleShape. I've made a 2d Vector of this class and want to push_back Rectangle shapes into it from a method of another class. I know my code won't work because I don't know where my RectangleShape will be push_back'ed into, x or y.
board::create(int x, int y){
cBoard = vector <vector <tile> >(x, vector< tile >(y, tile()));
int counter = 0;
RectangleShape t;
for(int i = 0; i < y; i++){
counter = 0;
if(i % 2 == 1){
counter = 1;
}
for(int ii = 0; ii < x; ii++){
if(counter % 2 == 0){
t.setFillColor(Color::Red);
cBoard.push_back(t);
cout << "red";
counter++;
}
else if(counter % 2 == 1){
t.setFillColor(Color::Green);
cBoard.push_back(t);
cout << "green";
counter++;
}
}
cout << endl;
}
}
The short answer is that you can't. Changing it to a 1D vector won't help either.
If you want to combine a container with inheritance, you almost certainly need the container to store some sort of pointer-like or reference-like thing, rather than storing the objects directly.
Depending on the situation, those might be std::unique_ptr, or std::reference_wrapper, or possibly just raw pointers in something like a Boost ptr_vector. One way or another, however, if you're using inheritance, you just about need to deal with the objects via something pointer-like or something reference-like rather than working directly with objects themselves.
The way to do this kind of thing is using dynamic_cast and store pointers, rather than values. For example:
RectangleShape r1 = new RectangleShape();
RectangleShape r2 = new tile();
tile* t1 = dynamic_cast<tile>(r1);
tile* t2 = dynamic_cast<tile>(r2);
In the above code snippet, t1 will be nullptr, because r1 is not a tile object. t2 will point to the correct tile object. Storing the pointers in a vector should probably be done with unique_ptr to prevent memory management issues.
If this is not what you want to do, if you want to actually create a tile object out of a RectangleShape object, then you would need to give the tile class a constructor that takes a RectangleShape object (preferably explicit), or create a function that takes a RectangleShape object and returns a tile object.
Finally, make sure when you're doing this that RectangleShape is actually the kind of object you would want to derive another class from. It must have a virtual destructor, and any overriden methods should also be virtual.
I am just starting to really understand Polymorphism, but still this is a new topic for me.
So here is my Problem: I have to classes, enemy and Bankrobber. However Bankrobber inherits from
enemy. I tried to make an array of 10 Bankrobbers. A global function should then use all members of the array to do something, well I guess this is a worthless description, so here is the code:
void UpdateEnemies(Enemy * p_Enemy, int counter) {
for(unsigned int i = 0;i < counter;i++) {
p_Enemy[i].Update();
}
}
int main(void) {
BankRobber EnemyArray[10];
Enemy * p_Enemy = new BankRobber(13,1);
UpdateEnemies(EnemyArray,10);
system("PAUSE");
};
I apologize for any language mistakes. I am not a native speaker
My actual Problem: This code is just for practicing, so the purpose is just to see 10 times Update on the console, for each member of the Array. So the function UpdateEnemys should call all the enemy.update functions. The method with the type casting is not exactly what I want, cause it is not dynamicly anymore, as there will be more enemy later on. Not only Bankrobbers.
Polymorphism only works on single objects, accessed by a reference or pointer to a base class. It does not work on an array of objects: to access array elements, the element size must be known, and that's not the case if you have a pointer to a base class.
You would need an extra level of indirection: an array of pointers to single objects, along the lines of
void UpdateEnemies(Enemy ** p_Enemy, int counter) {
for(unsigned int i = 0;i < counter;i++) {
p_Enemy[i]->Update();
}
}
int main() {
// An array of Enemy base-class pointers
Enemy * EnemyArray[10];
// Populate with pointers to concrete Enemy types
for (unsigned i = 0; i < 9; ++i) {
EnemyArray[i] = new BankRobber;
}
// Of course, the array can contain pointers to different Enemy types
EnemyArray[9] = new Dragon;
// The function can act polymorphically on these
UpdateEnemies(EnemyArray,10);
// Don't forget to delete them. Enemy must have a virtual destructor.
for (unsigned i = 0; i < 10; ++i) {
delete EnemyArray[i];
}
}
You should also consider using RAII types, such as containers and smart pointers, to manage these dynamic resources; but that's beyond the scope of this question.
Declaring an array of BankRobber like this
BankRobber EnemyArray[10];
But than acessing them through the base class pointer like this
Enemy * p_Enemy;
p_Enemy[i].Update();
Wouldn't work. That's because indexing an array p_Enemy[i] will be done by using the offcet sizeof(Enemy)
But sizeof(BankRobber) is probably bigger than from sizeof(Enemy), so p_Enemy[i] will end up in the wrong place
You should use a vector of pointers instead, like
std::vector<Enemy*>
That way you can also use polymorphism if you add pointers to different objects into the vector. And you don't need to pass the ugly int counter around
Indeed you didn't say exactly what is the problem.
Did you try casting inside your code? Something like:
void UpdateEnemies(Enemy * p_Enemy, int counter) {
BankRobber *pRobber = (BankRobber*)p_Enemy;
for(unsigned int i = 0;i < counter;i++) {
pRobber[i].Update();
}
}
I have a GameObject which contains an array of Shapes(assigned via malloc). Shapes have a list of Points in them and can be inherited to be Polygons.
Init code:
GameObject g1(true, true);
Color c(0, 0, 1, 0);
Point p(100, 100, 0);
Polygon s(p, c);
s.addPoint(p);
s.createRegularShape(4, 50.0f);
g1.addShape(s);
This is in the header.
Shape* shapes;
This is where it breaks (when I try to access the data)
void GameObject::draw(unsigned int gameTime)
{
if(visible)
{
for(int i = 0; i < count; i++)
shapes[i].draw();//Access violation happens here
}
}
This is how I add the Shape to the Shape array.
void GameObject::addShape(Shape const& shape)
{
if(count == size)
{
size += 4;
shapes = (Shape*)realloc(shapes, sizeof(Shape) * size);
}
shapes[count] = shape;
count++;
}
This is where I allocate memory for the Shape. This is called in the constructor when we need to allocate memory to the shapes array.
void GameObject::clearShapes(int size)
{
if(count > 0)
free(shapes);
shapes = (Shape*)malloc(sizeof(Shape) * size);
count = 0;
GameObject::size = size;
}
So basically, what am I doing wrong? How am I getting an access violation from this code? The data seems to all be the correct size and be legitimate.
When you use malloc(), the constructor of the objects is not run. As you can guess this can create all sorts of problems. Use new instead.
Do not use malloc() in C++ to create objects.
This:
Shape* shapes;
is an array of Shape objects, not an array of Shape pointers. That means the initial contents:
shapes = (Shape*)malloc(sizeof(Shape) * size);
and later:
shapes = (Shape*)realloc(shapes, sizeof(Shape) * size);
are not constructed. So when you later do:
shapes[count] = shape;
The assignment operator is called on shapes[count], which is a non-constructed Shape. It looks to me like you're waaay into undefined behavior here. Any kind of runtime error is possible.
Get rid of malloc() and realloc(), and instead use an std::vector<Shape> where you push_back() new Shapes. If you want to keep doing it with a plain dynamic array, then you should switch to an array of pointers instead:
Shape** shapes;
And only hold Shape pointers in there. This of course requires refactoring of your program logic, and I don't see why you would want to keep using malloc() and realloc().
I am relatively new to C++ programming, but am a C programmer of 10 years so am more comfortable with pointers to objects than I am with references to objects.
I'm writing a Solitaire game - is this design unsafe? Is there a better way?
Anyway, I have a class SolitaireGame:
class SolitaireGame:
{
public:
SolitaireGame( int numsuits = 1 );
private:
Deck * _deck;
vector<Card> _shoe;
};
The Deck is defined thus:
class Deck:
{
public:
Deck::Deck( vector<Card>& shoe );
~Deck();
int DealsLeft() const { return deals_left; }
Card * PullCard();
private:
int deals_left;
int num_each_deal;
deque<Card *> _cards;
};
The Deck constructor, takes a reference to a vector of Card objects ( the shoe, normally 104 cards ) and pushes a pointer to each card onto it's own deque of pointers.
Deck::Deck( vector<Card>& shoe )
{
vector<Card>::iterator iter = shoe.begin();
while( iter != shoe.end() )
{
_cards.push_front( &(*iter) );
iter++;
}
}
}
The shoe is created in the SolitaireGame constructor. Once this vector of dynamically created Card objects has been created - I then pass a reference to this vector to the constructor.
SolitaireGame::SolitaireGame( int numsuits ):_numsuits(numsuits )
{
Card * c;
vector<Card> _shoe;
for( int i = 0; i < NUM_CARDS_IN_SHOE; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_deck = new Deck( _shoe );
}
My idea was that the shoe would be the container for the actual memory for the Card objects and the Deck and Columns just handle pointers to those Card objects.
Just taking this snippet of code, you leak dynamically created cards.
Card * c;
vector<Card> _shoe;
for( int i = 0; i < NUM_CARDS_IN_SHOE; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_shoe.push_back( *c ) adds a copy of the Card object pointed to by c to the vector of Cards. You then fail to delete the original Card as created in the line before.
Allocating a vector of NUM_CARDS_IN_SHOE Cards can much more simply be achieved like this:
std::vector<Card> _shoe( NUM_CARDS_IN_SHOE );
Looking at your card structure, it looks like you have (or nearly have) strict ownership between objects so I don't think that you need to dynamically create your Cards.
Note that your local variable _shoe is shadowing the class variable _shoe. This probably isn't what you want as the local _shoe which you pass to the Deck constructor will go out of scope at the end of the constructor.
If you reorder you variables in SolitaireGame, you can probably do something like this:
class SolitaireGame:
{
public:
SolitaireGame( int numsuits = 1 );
private:
vector<Card> _shoe;
Deck _deck;
};
SolitaireGame::SolitaireGame( int numsuits )
: _shoe(NUM_CARDS_IN_SHOE)
, _deck(_shoe)
{
}
I've changed _deck from being a pointer. I'm using the fact that member variables are constructed in the order declared in the class definition, so _shoe will be fully constructed before it is passed as a reference to the constructor for _deck. The advantage of this is that I have eliminated the need to dynamically allocate _deck. With no uses of new, I know that I can't have any missed calls to delete as nothing needs to be deallocated explicitly.
You are right that you can store pointers to the Cards in _shoe in your _deck without any memory management issues, but note that you must not add or remove any of the Cards in the _shoe during the lifetime of the game otherwise you will invalidate all of the pointers in _deck.
I think there're two mistakes:
When you do _shoe.push_back( *c );, you're creating a copy of the Card object, so the memory reserved to c will never be freed. Btw, you should always check that for each new exists a complementary delete. Where is your delete?
In your Deck constructor you're saving pointers to objects that reside in the stack (vector<Card> _shoe;), so as soon as the SolitaireGame constructor ends, they will be deleted and your pointers will be invalid. EDIT: I see you've got another _shoe in your class, so it's not necessary to declare another _shoe local variable, in fact just by not declaring it you will solve this issue.
I hope this helps you a bit.
Initial thoughts:
In class SolitaireGame, you declare _shoe as:
vector<Card> _shoe;
but in the constructor you push heap objects on to it like this:
c = new Card();
_shoe.push_back( *c );
So, you need to declare it like this:
vector<Card*> _shoe;
You don't initialise variables in constructors, such as deals_left and num_each_deal in class Deck. I'll assume you left it out to not clutter up the code, but it's a good idea.
Class SolitaireGame creates and owns the Deck objects. It also has a Deck with pointers to SolitaireGame's Card objects. The ownership here is unclear - who deleted them? While having pointers to objects in multiple containers will work, it can make debugging more difficult, as there's scope for multiple deletion, using after it's been deleted, leaks etc. Perhaps the design could be simplified. Perhaps have Deck own the Card objects initially, and when they're removed, they get put into the vector in SolitaireGame, and don't exist in both at the same time.
In the constructor for SolitaireGame, you declare another vector of cards, which shadows the one declare in the class declaration. When you push the Card objects onto it, they'll not get pushed to the correct vector, which will go out of scope at the end of the constructor, and your class member will be empty. Just get rid of it from the constructor.
Anyway, I need a cup of tea. After that I'll take another look and see if I can suggest anything else.
I don't think the new keyword should appear anywhere in the code of these classes, and I don't see why you'd go through the trouble to share cards through pointers. Storing addresses of items held in a vector is recipe for disaster - you need to guarantee that there will be no modifications to the vector after you take the addresses, as it tends to move things around in memory without telling you.
Assuming a Card object doesn't store anything besides one or two ints, it would be a lot simpler to work with copies and values.
_deck = new Deck( _shoe );
Again, I don't see a slightest reason to increase complexity of the program by allocating an object containing two ints and a deque dynamically.
If you are worried about cost of copying some of the larger classes you have (which I would estimate has zero impact on perceived performance here), then simply don't copy them, and pass them around by const reference (if you don't need to mutate the instance), or non-const reference/pointer otherwise.
This program will leak memory , Want to find out why ? or how ?
push_back
Do remember this call do not insert your supplied element , But creates a copy of it for own use. Read this for detail
So
Card *c = new Card(); // This is on heap , Need explicit release by user
If you change it to
Card c; // This is on stack, will be release with stack unwinding
Copy below program and execute it, {I simply added logging}, try with both option, above
#include<iostream>
#include <vector>
#include <deque>
using namespace std;
const int NUM_CARDS_IN_SHOE=120;
class Card
{
public:
Card()
{
++ctr;
cout<<"C'tor callend: "<<ctr<<" , time"<<endl;
}
~Card()
{
++dtr;
cout<<"D'tor called"<<dtr<<" , time, num still to release: "<<((ctr+cpy)-dtr)<<endl;
}
Card& operator=(const Card & rObj)
{
return *this;
}
Card (const Card& rObj)
{
++cpy;
cout<<"Cpy'tor called"<<cpy<<endl;
}
private:
static int ctr,dtr,rest,cpy;
};
int Card::ctr;
int Card::dtr;
int Card::rest;
int Card::cpy;
class Deck
{
public:
Deck::Deck( vector<Card>& shoe );
~Deck();
int DealsLeft() const { return deals_left; }
Card * PullCard();
private:
int deals_left;
int num_each_deal;
std::deque<Card *> _cards;
};
Deck::Deck( vector<Card>& shoe )
{
vector<Card>::iterator iter = shoe.begin();
while( iter != shoe.end() )
{
_cards.push_front( &(*iter) );
iter++;
}
}
class SolitaireGame
{
public:
SolitaireGame( int numsuits = 1 );
private:
Deck * _deck;
std::vector<Card> _shoe;
};
SolitaireGame::SolitaireGame( int numsuits )
{
Card * c;
vector<Card> _shoe;
for( int i = 0; i < numsuits; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_deck = new Deck( _shoe );
}
int main()
{
{
SolitaireGame obj(10);
}
int a;
cin>>a;
return 0;
}
Since such a game object always has its own deck you should consider making the Deck object a real member inside SolitairGame -- not just a pointer. This will make life-time management of the deck object much simpler. For example, you won't need a custom destructor anymore. Keep in mind that STL containers contain copies. If you write something like
myvector.push_back(*(new foo));
you have a memory leak.
In addition, storing pointers to elements of a vector is dangerous because the pointers (or iterators in general) might become invalid. For a vector this is the case when it needs to grow. An alternative is std::list which keeps iterators valid after insertion, deletion, etc.
Also, keep in mind that in C++ structs and classes usually get implicit copy constructors and assignment operators. Honor the rule of three. Either disallow copying and assignment or make sure that resources (including dynamically allocated memory) is properly managed.