I'm working on a simple game using C++ and Allegro. I am running into an Access violation runtime error regarding a vector of structs that contain unique_ptrs to ALLEGRO_BITMAPs.
Here is my struct declaration.
struct Skin {
std::unique_ptr<ALLEGRO_BITMAP> img;
Skin();
Skin(ALLEGRO_BITMAP*);
Skin& operator=(const Skin& s);
Skin(const Skin& s);
};
And here are the definitions of the constructors in another file.
Skin::Skin() {
img.reset();
}
Skin::Skin(ALLEGRO_BITMAP* bitmap) {
img.reset(bitmap);
}
Skin::Skin(const Skin& s) {
img.reset(s.img.get());
}
Skin& Skin::operator=(const Skin& s) {
img.reset(s.img.get());
return *this;
}
Here is the code that gets called before my access violation.
generateBase(world, display.get());
Which calls this function.
void generateBase(World& world, ALLEGRO_DISPLAY* display) {
int x = TILESIZE - WIDTH;
int y = HEIGHT - TILESIZE;
int groundWidth = 3 * WIDTH - 2 * TILESIZE;
Point min{ x, y };
Point max{ x + groundWidth, y + (int)TILESIZE };
ALLEGRO_BITMAP* black = al_create_bitmap(groundWidth, TILESIZE);
ALLEGRO_BITMAP* white = al_create_bitmap(groundWidth, TILESIZE);
al_set_target_bitmap(black);
al_clear_to_color(al_map_rgb(0, 0, 0));
al_set_target_bitmap(white);
al_clear_to_color(al_map_rgb(255, 255, 255));
al_set_target_bitmap(al_get_backbuffer(display));
std::cout << "Errors incoming!" << endl;
createPlayer(world, x, y, 0, 0, 5, vector < AABB > { AABB(min, max) }, vector < Skin > { Skin(black), Skin(white) });
std::cout << "Did we make it?" << endl;
}
Which in turn calls this function.
unsigned int createPlayer(World& world, int x, int y, float dx, float dy, float speed, vector<AABB>& mesh, vector<Skin>& imgs) {
unsigned int entity = newEntityIndex(world);
world.masks[entity].set(COMPONENT_TYPE);
world.masks[entity].set(COMPONENT_POINT);
world.masks[entity].set(COMPONENT_UNITVECTOR);
world.masks[entity].set(COMPONENT_SPEED);
world.masks[entity].set(COMPONENT_COLLISIONMESH);
world.masks[entity].set(COMPONENT_SKINLIST);
world.types[entity] = TYPE_PLAYER;
world.points[entity] = Point(x, y);
world.unitVectors[entity] = UnitVector(dx, dy);
world.speeds[entity] = Speed(speed);
world.collisionMeshes[entity].mesh = mesh;
cout << "Starting vector copy" << endl;
for (auto skin : imgs) {
world.skinLists[entity].imgs.push_back(move(skin));
}
cout << "Ending vector copy" << endl;
return entity;
}
Here is my deleter for unique_ptr.
namespace std {
template<>
class default_delete < ALLEGRO_BITMAP > {
public:
void operator()(ALLEGRO_BITMAP* ptr) {
cout << ptr << endl;
al_destroy_bitmap(ptr);
}
};
}
Here is the output.
Errors incoming!
Starting vector copy
00AF9468
00AF9468
When I modified my createPlayer call in generateBase by removing Skin(white), the output changed to.
Errors incoming!
Starting vector copy
00799468
Ending vector copy
00799468
The change in output had me a bit puzzled, but my biggest question is what do I need to change about how I copy my vector of structs of unique_ptrs so that I don't try to delete the same pointer twice.
Thanks in advance!
The first thing to understand is you can only have one std::unique_ptr object containing a pointer to a particular object. Your Skin(const Skin& s) constructor violates this principle, resulting in two copies of a unique_ptr. If you have an object containing unique_ptr members, you'll need to do one of the following:
Not have a copy constructor or assignment operator.
In the copy constructor and/or assignment operator, allocate a new copy of the underlying resource. This would require calling al_clone_bitmap to duplicate the resource.
Second, when you are holding a resource in a unique_ptr, you want to initialize the unique_ptr at the same location where you create the resource. For example, instead of creating a local variable ALLEGRO_BITMAP* black, use the following:
std::unique_ptr<ALLEGRO_BITMAP> black(al_create_bitmap(groundWidth, TILESIZE));
Since this code is creating the unique_ptr directly from the result of al_create_bitmap, you'll want to remove the Skin constructor that takes an ALLEGRO_BITMAP* and replace it with this:
Skin::Skin(std::unique_ptr<ALLEGRO_BITMAP>&& bitmap)
: img(bitmap)
{
}
You can then create a Skin by moving your unique_ptr into it:
Skin(std::move(black))
Putting the above together, a working copy constructor might look like the following. It's not particularly efficient, but it's safe.
Skin::Skin(const Skin& s)
: img(al_clone_bitmap(s.img.get()))
{
}
The problem is here:
Skin::Skin(const Skin& s) {
img.reset(s.img.get());
}
Skin& Skin::operator=(const Skin& s) {
img.reset(s.img.get());
You are stealing the raw pointer from one unique_ptr and assigning it to another one. Now unique_ptr belongs to the RAII category. They expect to own the lifetime of an object as long as they are alive.
When you do this
img.reset(s.img.get());
You took out the pointer from one unique_ptr and handed over to the other unique_ptr. Now unique_ptr1 believes that it own the underlying object unaware that there is another unique_ptr2 that believes the same. So when they die they will happily free the memory allocated for _Ptr. So your code is bound to end up accessing/freeing memory which has already being freed by the first unique_ptr which dies.
You must either move the unique_ptr (thereby yielding ownership) or explicitly calling release on s.img
Related
I am making my "version" of Space Invaders in C++ using SFML library but I have a problem when I try to delete an invader.
I have this error in my code:
Enemy &Enemy::operator =(const Enemy &)': attempting to reference a deleted function
I tried to check other solutions that were recommended in this forum but I either didn't understand them or it was a different case.
EnemyControler.cpp
EnemyControler::EnemyControler()
{
Enemy::Type types[] = {
Enemy::Type::Squid, Enemy::Type::Crab, Enemy::Type::Crab,
Enemy::Type::Octopus, Enemy::Type::Octopus
};
for (int y = 0; y < 5; y++) { // Add enemies to the vector
for (int x = 0; x < 11; x++){
float enemyX = x * 40 + (gapBetweenEnemies * x * 3) + Enemy::enemyWidth; // Make horizontal gap between them
float enemyY = y * 40 + (gapBetweenEnemies * y) + Enemy::enemyHeight; // Make vertical gap between them
enemies.emplace_back(sf::Vector2f{ enemyX, enemyY }, types[y]); // Add them to the vector
}
}
}
void EnemyControler::destroyEnemy()
{
for (auto iterator = begin(enemies); iterator != end(enemies);) {
auto& enemy = *iterator;
if (enemy.isAlive()) {
iterator++;
}
else {
iterator = enemies.erase(iterator);
}
}
}
Problem is in destroyEnemy function. Specifically in iterator = enemies.erase(iterator);
EnemyControler.h
class EnemyControler
{
public:
EnemyControler();
void destroyEnemy();
private:
const int gapBetweenEnemies = 10;
std::vector<Enemy> enemies;
};
Enemy.cpp
Enemy::Enemy(sf::Vector2f startingPosition, Type type) :
Collidable(enemyWidth, enemyHeight), newPosition(startingPosition), enemyType(type), startingPosition(startingPosition)
{
}
Enemy.h
class Enemy : public Collidable
{
public:
enum class Type // enum for different looking enemies
{
Crab, Octopus, Squid
};
Enemy(sf::Vector2f startingPosition, Type type);
constexpr static float enemyWidth = 30.0f;
constexpr static float enemyHeight = 30.0f;
private:
sf::Vector2f newPosition;
Type enemyType;
const sf::Vector2f startingPosition;
};
Collidable.cpp
Collidable::Collidable(float width, float height) :
spriteSize(width, height)
{
}
Collidable.h
class Collidable
{
public:
Collidable(float width, float height);
private:
sf::Vector2f spriteSize;
};
If there isn't an easy way of fixing this problem or this problem could be fixed only by rewriting all code maybe you could suggest another way of deleting invader from the vector.
If a class has a const member variable, then the copy assignment operator for that class operator= is default-deleted by the compiler.
From https://en.cppreference.com/w/cpp/language/copy_assignment :
A defaulted copy assignment operator for class T is defined as deleted if any of the following is true:
- T has a non-static data member of non-class type (or array thereof) that is const;
This is because the compiler can't guess what it means to copy assign object A into object B, if objects of their class contain a const member variable. Should the compiler just ignore that particular member variable? Should the compiler guess that you mean it to be const, except when copy assigning, then it's okay just this once - I'll look the other way? The compiler has no idea what you would prefer, so it just deletes it.
One option is to explicitly define a copy assignment operator for your class.
However, startingPosition is already declared private, so there's little chance of anything outside of the class inadvertently changing it. I recommend just removing the const specifier.
Why does the copy assignment operator matter? I'm trying to delete things, not copy assign them
When an element is erased from a vector, all elements in the vector "above" the erased element need to be moved down to fill the gap. This happens via the copy assignment operator.
From https://en.cppreference.com/w/cpp/container/vector/erase :
Complexity
Linear: the number of calls to the destructor of T is the same as the number of elements erased, the assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements
I added a destructor to some code and it seems to be calling early and causing problems. I added a debug statement to see where it is being called and that made me even more confused. I understand that managing my own memory is not best practice but I wanted to try it out myself.
This is basically my GameObject class:
class GameObject
{
public:
int xCoord = 0, yCoord = 0, prevX, prevY;
int status = 0, weight = -1;
int id = -1;
GameObject(CommandComponent* commands,
PhysicsComponent* physics,
GraphicsComponent* graphics)
: commandComponent(commands),
physicsComponent(physics),
graphicsComponent(graphics)
{};
~GameObject()
{
std::cout << "Destructor called " << id << std::endl;
delete commandComponent;
delete physicsComponent;
delete graphicsComponent;
};
void update(World& world, int command, sf::Time dt)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
graphicsComponent->update(*this, dt);
};
void update(World& world, int command)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
};
sf::Sprite draw()
{
return *(graphicsComponent->draw());
};
void setCoords(int x, int y)
{
prevX = xCoord;
xCoord = x;
prevY = yCoord;
yCoord = y;
};
void setId(int newId)
{
id = newId;
}
private:
CommandComponent* commandComponent = NULL;
GraphicsComponent* graphicsComponent = NULL;
PhysicsComponent* physicsComponent = NULL;
};
This is the createPlayer Method:
GameObject* createPlayer(sf::Texture* text)
{
return new GameObject(new PlayerCommandComponent(), new PlayerPhysicsComponent(), new PlayerGraphicsComponent(text));
};
This is a method I invoke to add the new object to a vector based on if it is an active object or an inactive one I also add it to an array :
void World::addObject(GameObject object, int id, int type){
object.setId(id);
if (type == 0)
{
inactiveObjects.push_back(object);
}
else if (type == 1)
{
activeObjects.push_back(object);
}
}
Finally this is my test code that creates the Game Objects and calls the above function and where I see the destructors being called from:
void World::test()
{
// Player
std::cout << "Starting to create id 0\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 0, 1);
activeObjects.at(0).setCoords(3, 3);
activeObjects.at(0).weight = 10;
std::cout << "Created id 0\n";
// Test Objects
std::cout << "Starting to create id 1\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 1, 1);
activeObjects.at(1).setCoords(3, 4);
activeObjects.at(1).weight = 7;
std::cout << "Created id 1\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 2, 1);
activeObjects.at(2).setCoords(5, 4);
activeObjects.at(2).weight = 2;
addObject((*createPlayer(&(mTextures.get(Textures::Enemy)))), 3, 1);
activeObjects.at(3).setCoords(6, 6);
activeObjects.at(3).weight = -1;
addObject((*createPlayer(&(mTextures.get(Textures::Enemy)))), 4, 1);
activeObjects.at(4).setCoords(1, 1);
activeObjects.at(4).weight = 0;
std::cout << "Done Creating Test Objects\n";
I guess my main question is how come the Destructors are being called? Im assuming its related to how I'm constructing the object in the createPlayer method, Perhaps it's going out of scope after I return it but I thought using the new keyword would prevent that from happening? I'm puzzled here.
Several things at play here.
GameObject* createPlayer(sf::Texture* text)
returns a dynamically allocated GameObject. This could be done better, read up on std::unique_ptr, but there is nothing strictly wrong here. I mention it mostly to point out std::unique_ptr and set up
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 0, 1);
because this is where thing start to go wrong. When you find code that uses new and dereferences and discards the the result, you're looking at a memory leak. You've lost the pointer to the dynamically allocated object and without the pointer it is next to impossible to find the allocation again so that you can delete it.
Storing the dereferenced object will invoke either the copy constructor or the assignment operator and at this point you need to consider The Rule of Three: If you need a to define a custom destructor, you probably need to define a custom assignment operator and a copy constructor. This is a standard example of when you need to observe the Rule of Three. What goes wrong is well-explained in the Rule of Three Link, so stop, read, and understand it before going any further. Failure to do this means the rest of this answer will be nigh-useless to you.
You cannot write good, non-trivial C++ code without a firm grip on the Rule of Three and all of its friends.
You can step around the Rule of Three here by changing
void World::addObject(GameObject object, int id, int type)
to
void World::addObject(GameObject * object, int id, int type)
and pass object by reference. This doesn't help much because
inactiveObjects.push_back(object);
is expecting an object, not a pointer.
You can change that as well, but should you? std::vector is at its absolute best when it directly contains an object. Pointers lead to pointer chasing, poor caching behaviour and ultimately suuuhhhfering. Don't store pointers unless you have a compelling reason to do so.
And if you do, manage the pointers with a std::unique_ptr beginning to end.
What I would do:
Jump straight over the Rule of Three and go to The Rule of Five.
Exterminate as many dynamically allocated variables as possible so that I don't need to do much work, if any, with point 2. This means no pointers for (or in) commandComponent, physicsComponent and graphicsComponent if possible.
Add a move constructor and move assignment operator to GameObject as well as CommandComponent, PhysicsComponent, and GraphicsComponent. Keep all resource management as close to the resource as possible. This allows you to keep higher level classes as ignorant as possible. If GraphicsComponent knows how to copy and move itself, GameObject doesn't need to know how to move it. This allows you to take advantage of The Rule of Zero, and the Rule of Zero should be what you strive for in all of your classes.
Use move semantics to get a GameObject, not a GameObject* from createPlayer down to the activeObjects and inactiveObjects vectors.
Enjoy the reduced memory management load.
I have two classes, in the example added Rectangle and Rectangles. The goal is to make one Rectangles object which holds references to multiple Rectangle objects.
If I change r by r.set_values(4,4) then off coarse r.area() is changed. However if I call rectangles.rects[0].area() it remains 12, and therefore is not changed.
As I understood I am making a reference of r in rectangles, however this seems to be wrong.
How to achieve this?
The code is available here
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
Rectangle* rects;
int nRects;
};
Rectangles::Rectangles(int n) {
rects = new Rectangle[n];
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = *r;
nRects++;
}
int main() {
Rectangle r;
Rectangles rectangles(5);
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() before change:"<<rectangles.rects[0].area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() after change:"<<rectangles.rects[0].area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0].area() before change:12
r.area() after change:16
rectangles.rects[0].area() after change:12
What is wrong with your code is your definition of Rectangles. It stores a pointer (or an array) to a Rectangle. What you want here is not an array of Rectangle's, but an array of references to Rectangle's. Here, the references shall be pointers, so you need to change this accordingly :
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
// Rectangle* rects;
// What you really want :
Rectangle** rects;
int nRects;
};
But then you also need to change the implementation :
Rectangles::Rectangles(int n) {
rects = new Rectangle*[n]; // Array of pointers
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = r; // r is a pointer : just store it, no dereferencing
nRects++;
}
However, this is a bad design : you should not have to use any of these : pointer to pointer (or 'raw array' of pointers), new, and a class whose only purpose is to store an array of things. This is because you already have better tools for this : smart pointers (although you do not need them here either), arrays and dynamic arrays (or vectors).
So, if I were you, this is how I would rewrite your code :
#include <iostream>
#include <vector>
class Rectangle {
public:
void setSize(int w, int h);
int area();
private:
int width, height;
};
void Rectangle::setSize(int w, int h) {
width = w;
height = h;
}
int Rectangle::area() {
return width * height;
}
int main() {
Rectangle r;
std::vector<Rectangle*> rectangles;
r.setSize(4, 3);
rectangles.push_back(&r);
std::cout << "r.area() before change : " << r.area() << std::endl
<< "rectangles[0]->area() before change : "
<< rectangles[0]->area() << std::endl;
r.setSize(4, 4);
std::cout << "r.area() after change : " << r.area() << std::endl
<< "rectangles.rects[0]->area() after change : "
<< rectangles[0]->area() << std::endl;
return 0;
}
Edit :
You might wonder why I used a raw pointer instead of a smart pointer (since I told you to avoid pointers to pointer). This is quite simple : no smart pointer would fit the matter. Let us see why.
std::unique_ptr keeps sole ownership of the object. What if you want another reference to it ? Also, if you ever destroy this smart pointer via std::vector's erase, it would also destroy your object. So if you access it afterwards, you would get some dirty error.
std::shared_ptr keeps shared ownership of the object. Sure, you can have another reference to your object, but the same thing happens if you destroy the pointer. Also, it has some overhead, and is not so easy to use correctly.
std::weak_ptr works with std::shared_ptr, nothing more to say.
A raw pointer, on the contrary, only needs you to ensure that the lifetime of the object is longer or equal to its own lifetime, so that you can always access your object via the pointer. And that is all.
Finally, here is a general rule of thumbs (that I use) :
unique_ptrs are for sole ownership
raw pointers mean whoever gave me the raw pointer guarantees the lifetime of that object to match or exceed my lifetime.
shared_ptrs are for shared ownership
weak_ptrs are for when a system wants to check if the object still exists before using it. This is rare in my code since I find it cleaner to have a system guarantee the lifetime of anything it passes it's subsystems (in which case I use a raw pointer)
class Rectangles {
public:
void addRectangle(Rectangle* r);
vector<Rectangle *> rects;
};
void Rectangles::addRectangle(Rectangle* r) {
rects.push_back(r);
}
int main() {
Rectangle r;
Rectangles rectangles;
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() before change:"<<rectangles.rects[0]->area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() after change:"<<rectangles.rects[0]->area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0]->area() before change:12
r.area() after change:16
rectangles.rects[0]->area() after change:16
I'm making a game with SDL that used libconfig to read some settings from a file. The problem is that I made a class called ClipList that contains a std::vector<SDL_Rect> to store the settings but when trying to add SDL_Rect objects to the vector, for some reason push_back does nothing and I end up with an empty vector.
This is the class:
class ClipList
{
public:
ClipList();
ClipList(int);
virtual ~ClipList();
void addClip(int,int,int,int);
void getClip(int,SDL_Rect*);
int getLength();
protected:
private:
std::vector<SDL_Rect> clips;
};
ClipList::ClipList(int l)
{
clips.reserve(l);
}
void ClipList::addClip(int x,int y,int w,int h){
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
clips.push_back(rect);
}
void ClipList::getClip(int i,SDL_Rect* rect){
rect = &(clips.at(i));
}
int ClipList::getLength(){
return clips.size();
}
And this is the function where I initialize the ClipList object. This function gets called from main.
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips){
const Setting& root = placlips->getRoot();
int x,y,w,h;
try{
Setting& clipsett = root["clips"];
int cliplen = clipsett.getLength();
clips = new ClipList(cliplen);
flipclips = new ClipList(cliplen);
for(int i=0;i<cliplen;i++){
const Setting& c = clipsett[i];
if(!(c.lookupValue("x",x)&&c.lookupValue("y",y)&&c.lookupValue("w",w)&&c.lookupValue("h",h))){
continue;
}
clips->addClip(x,y,w,h);
}
}catch(const SettingNotFoundException &nfex){
cerr << "Setting not found at" << nfex.getPath() << endl;
}
}
Regardless of whether the ClipList objects get initialized in main or set_clips, clips.push_back(rect) doesn't work. The capacity of the vector changes but no object gets stored so I end up with a segfault if I try to do anything else with the vector, even checking if the vector is empty or not.
I am going to guess, the signature of the function
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips);
is the culprit. You are allocating memory for clips and flipclips in this function but since the pointers are passed by value, the calling function does not see the allocated memory.
If you change the function signature to:
void set_clips(Config* placlips, ClipList*& clips, ClipList*& flipclips);
your problems should go away.
clips.push_back(rect) is working fine. Your set_clips function allocates new ClipList instances but does not pass those pointers back to the caller. The caller is probably attempting to use a garbage pointer as an initialise instance and that is why you are getting a segfault.
You need to pass the created objects back. You should use something like std::shared_ptr<> to do that instead of bare pointers.
Update on how to do this without using std::shared_ptr<>:
You need to keep track of ownership and deal with exceptions. In terms of the actual passing, the rule I use (originally from Lakos in "Large Scale C++ Software Design") is that parameters that are return values (as you are attempting to use them) are pointers, and read-only parameters are by value or const-reference. Return values come first.
So, your set_clips function should look like this:
void set_clips(ClipList** clips, ClipList** flip_clips, Config const& placlips)
When you call set_clips you pass a pointer to each pointer that will receive the allocated value, and pass a const-reference to the placlips object that is not modified by the function.
You would all it something like this:
ClipList* clips = 0;
ClipList* flip_clips = 0;
set_clips(&clips, &flip_flips, placlips);
// ... then do whatever comes next.
But combining those rules with std::shared_ptr<> or boost::shared_ptr<> is better and the "modern C++" style.
I have a problem. I need to clone objects class containing pointers. An example of the problem is in the following code:
#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <vector>
class CPoint
{
protected:
int m_x;
int m_y;
int *m_p;
public:
CPoint();
CPoint(int x, int y);
~CPoint();
CPoint* clone();
static CPoint* clone(CPoint& p);
int getX();
int getY();
void setX(int x);
void setY(int y);
void toString();
};
int CPoint::getX()
{
return m_x;
}
int CPoint::getY()
{
return m_y;
}
void CPoint::setX( int x )
{
m_x = x;
}
void CPoint::setY( int y )
{
m_y = y;
}
void CPoint::toString()
{
std::cout << "(" << m_x << ", " << m_y<< ", " << *m_p << ")" << std::endl;
}
CPoint::CPoint( int x, int y )
{
m_x = x;
m_y = y;
m_p = new int();
*m_p = x + y;
}
CPoint::CPoint()
{
m_p = new int();
*m_p = 1000;
}
CPoint* CPoint::clone()
{
CPoint *p = new CPoint();
*p = *this;
return p;
}
CPoint* CPoint::clone( CPoint& p )
{
CPoint *q = new CPoint();
*q = p;
return q;
}
CPoint::~CPoint()
{
if (m_p) {
delete m_p;
m_p = NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);
p1->toString();
p2->toString();
CPoint *p3;
p3 = CPoint::clone(*p1);
p3->toString();
CPoint *p4;
p4 = p2->clone();
p4->toString();
p1->setX(50);
p1->setY(60);
p2->setX(80);
p2->setY(90);
p3->toString();
p4->toString();
delete p1;
delete p2;
delete p3;
delete p4;
int a;
std::cin >> a;
return 0;
}
The problem I have with the variable m_p. When clone objects p1 and p2 on p3 and p4, the memory addresses p1 and p3 are different but m_p address is the same. Obviously, when remove p1, p3 removal fails. With p2 and p4 is the same.
How I can clone a CPoint class object?
You seem to be applying the rules of some other Java like language to C++.
This is a fundamental problem and going to lead to all sorts of problems in the long run.
You need to learn the idioms of C++.
In C++ you want to use C++ strings (std::string) not the C-String interface.
#include <string.h> // C-Interface
// What you really want
#include <string> // C++ Interface
If your class contains a pointer then you are probably doing something wrong. RAW pointers should be wrapped in a smart pointer (or containers) to control their lifespan correctly. If you put a pointer into an business class you are breaking the separation of concerns principle.
class CPoint
{
protected:
int m_x;
int m_y;
int *m_p; // What is it supposed to be?
// Who owns it?
Since your class had a pointer it broke the rule of three.
If you wanted to manage the pointer in this class (and you don't (breaking separation of concerns)) then you should have implemented the rule of three (rule of five in C++11) (look it up). If you want to learn how handle a RAW pointer look here https://stackoverflow.com/a/1846409/14065
There is no need for a clone method. This is what the copy constructor is for. You are not writing a class that needs to be cloned (otherwise it would have had a virutal destructor). Your class is not polymorphic and will not be derived from. Thus a copy constructor will work perfectly.
CPoint* clone();
static CPoint* clone(CPoint& p);
// Copy constructor looks like this:
CPoint(CPoint const& rjs)
// Assignment operator looks like this:
CPoint& operator=(CPoint& rhs)
But non of this is required if correctly wrap your RAW pointer in an appropriate class. The compiler generated default versions of these methods will work fine.
Good way to completely destroy encapsulation.
int getX();
int getY();
void setX(int x);
void setY(int y);
To string! Poop. What you really want is a serialization method.
void toString();
// serializer look like this:
friend std::ostream& operator<<(std::ostream& stream, CPoint const& data)
{
// Convert CPoint (data) to the stream.
return stream;
}
In C++ we do not dynamically create objects unless we need to.
And here you do not need to. Creating local objects works better because their lifespan is guaranteed even in the presence of exceptions.
// Rather than dynamically creating them
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);
// Just declare two local variables:
CPoint p1 = CPoint(10, 20);
CPoint p2(30, 40); // Alternative to the above but means the same.
// Much better to use operator<<
// Also shows the functions are badly named. You are not converting to string.
// but rather printing them to a stream.
p1->toString();
p2->toString();
std::cout << p1;
myFileStream << p2; // allows you to easily specify the actual stream.
Copy constructor work much better for copying an object
CPoint *p3;
p3 = CPoint::clone(*p1);
// If we were still using pointers.
CPoint* p3 = new CPoint(p1);
// But much nicer to not even use pointers
CPoint p3(p1);
Its usually a design mistake if you ever see manual call to delete in a function.
delete p1;
delete p2;
delete p3;
delete p4;
If you have pointers wrapping them in smart pointers (or container) like classes makes them exception safe to use. This is because for local objects the destructor is guaranteed to be called and thus your object will correctly deleted the pointer when it goes out of scope. Currently this code is not exception safe and will leak if an exception propagates passed them.
Small note: main() is special. If you don't specify a return value the compiler plants return 0; for you. If your application has no error state best to use this functionality as a sign to other developer that your code will always exit cleanly.
return 0;
I would re-write like this:
#include <iostream>
#include <string>
#include <vector>
class CPoint
{
protected:
int m_x;
int m_y;
std::vector<int> m_p;
public:
// If you don't explicitly initialize m_x and m_y them
// they will have indeterminate (random) values.
CPoint() : m_x(0), m_y(0) {m_p.push_back(1000);}
CPoint(int x, int y) : m_x(x), m_y(y) {m_p.push_back(x + y);}
int getX() { return m_x;}
int getY() { return m_y;}
void setX(int x) { m_x = x;}
void setY(int y) { m_y = y;}
friend std::ostream& operator<<(std::ostream& stream, CPoint const& d)
{
return stream << "(" << d.m_x << ", " << d.m_y<< ", " << d.m_p[0] << ")" << std::endl;
}
};
int main(int argc, char* argv[])
{
CPoint p1(10, 20);
CPoint p2(30, 40);
std::cout << p1 << p2;
CPoint p3(p1);
std::cout << p3;
CPoint p4(p2);
std::cout << p4;
p1.setX(50);
p1.setY(60);
p2.setX(80);
p2.setY(90);
std::cout << p1 << p2 << p3 << p4;
int a;
std::cin >> a;
}
In this example is an integer but may be any type. The question I had was like to clone an object that contains a pointer to another type.
I believe that there are basically two situations here: you want the containing object to own the pointed-to object; or you don't want the containing object to own the pointed-to object.
Let's start with non-owning. What's the tool that C++ provides to represent non-owning pointers? Well, regular pointers are non-owning. And how do you copy a regular pointer? You do nothing. You let the compiler deal with it, generating the correct copy constructor that you can use at will (and while you're at it, let the compiler generate a destructor as well).
And what about owning? What's the tool for owning pointers? Well, for most cases you don't even need a pointer for that: just store a value directly and, again, let the compiler generate the correct copy constructor (and a destructor too!). In the example provided int m_p; would work nicely.
There is an annoyance in this situation when polymorphic base classes are involved: copying may cause slicing. Does C++ provide a tool for this situation? Sadly, it doesn't. You have to write it by hand. But do yourself a favour and don't mix these concerns with the rest of the class (Single Responsibility Principle).
Write a reusable class (bonus points: make it a template) that owns a single pointer, cleans it up on destruction, and performs a polymorphic copy (a common idiom involves a virtual clone function) in the copy constructor. Then put a value of that reusable class in your CPoint and... you guessed it! Let the compiler generate the correct copy constructor.
In addition to shallow-copying the immediate data members m_x and m_y, you need to deep-copy the pointer member m_p. Since you haven't shown the constructor for this class or what m_p really points to, I'm going to assume that m_p points to the first element of an array of int. Deep-copying this entails:
Instantiate a new array of int that is the same (or larger) size as the original array
Copy each element from the original array to the new array
Set m_p in the cloned object to point to the first element of this new array
An example of how this might be done:
CPoint* CPoint::clone(CPoint& rhs)
{
CPoint* ret = new CPoint;
ret->m_x = rhs.m_x;
ret->m_y = rhs.m_y;
size_t m_p_count = /* somehow determine the size of rhs.m_p */;
ret->m_p = new int[m_p_count];
std::copy(&rhs.m_p[0], &rhs.m_p[m_p_count], ret->m_p);
return ret;
}
A few notes about your code:
You would be better off using a vector<int> instead of a raw pointer to an array of int.
Barring #1, you should be using smart pointers instead of raw pointers
I don't see any way in the code above to determine the size of the array. This would be easy if you used a vector<int> -- just call vecctor<int>::size(). You need to know the size of the array in order to make a copy of it, obviously.
A clone() type function is generally only useful when making a copy of a polymorphic object via a base class pointer. Since your class, and your useage of it, does not fall in to this category, a clone() function is not the right way to go in the first place. Consider using a copy constructor and a copy assignment operator instead, and don't forget to also implement a destructor. Better still, avoid all of this stuff altogether and follow the Rule of Zero.
You must reallocate memory for all pointers within CPoint and copy their data into new memory. In your case you have to do following operation:
CPoint clone()
{
CPoint p;
p = *this;
p.m_p = new int();
*p.m_p = *m_p;
return p;
}
You have to ask yourself: Does each instance of your object "own" the object it points to, or do they all refer to a common object owned by something else?
When you have a case of ownership, each instance must point to an individual copy. That means that you don't have to copy the pointer, you have to create a clone of the object it points to and assign this new object to the pointer of the copy.
Assuming that m_p points to only one integer (and not a whole array), cloning can be done like this:
CPoint* CPoint::clone()
{
CPoint* cloned = new CPoint(m_x, m_y);
if (m_p)
{
cloned->m_p = new int;
*cloned->m_p = *m_p;
}
return cloned;
}
Note that such a member pointer has the sole purpose of adding the additional possibility of having a NULL-value - which can have a separate meaning.
Note also that the following has to be done to avoid memory leaks and heap corruption:
The copy constructor and assignment operator have to be "disabled" (declared private)
The destructor must delete m_p.