I have a class
class Invader
{
public:
Invader();
~Invader();
public:
void Init(InvaderTypes invadertype, CIw2DImage *AlienImage);
void Update(float dt);
void Render();
void SetAlienImage(CIw2DImage *image){ ImageAlien = image; }
void setVisible(bool show) { Visible = show; }
bool isVisible() const { return Visible; }
Iw2DSceneGraph::CSprite *AlienSprite;
Iw2DSceneGraph::CAtlas *AlienAtals;
CIw2DImage *ImageAlien;
std::list<Bullet*> *Bullets;
CIwFMat2D Transform; // Transform matrix
bool Visible; // Sprites visible state
bool Canfire;
};
void Invader::Init(InvaderTypes invadertype, CIw2DImage *AlienImage)
{
if (invadertype == InvaderTypes::TOP_ALIEN)
{
//SetAlienImage(AlienImage);
mImageAlien = AlienImage;
// Create EnemyTop atlas
int frame_w = (int)(mImageAlien->GetWidth() / 2);
int frame_h = (int)(mImageAlien->GetHeight());
AlienAtals = new CAtlas(frame_w, frame_h, 2, mImageAlien);
AlienSprite = new CSprite();
AlienSprite->m_X = 0;
AlienSprite->m_Y = 0;
AlienSprite->SetAtlas(AlienAtals);
AlienSprite->m_W = (float)AlienAtals->GetFrameWidth();
AlienSprite->m_H = (float)AlienAtals->GetFrameHeight();
AlienSprite->m_AnchorX = 0.5;
AlienSprite->SetAnimDuration(2);
}
else if (invadertype == InvaderTypes::MIDDLE_ALIEN)
{
}
else if (invadertype == InvaderTypes::LAST_ALIEN)
{
}
Visible = true;
Bullets = new std::list<Bullet*>();
Canfire = true;
}
Invader::Invader()
{
}
Invader::Invader(const Invader&other)
{
AlienAtals = new CAtlas();
AlienSprite = new CSprite();
*AlienAtals = *other.AlienAtals;
*AlienSprite = *other.AlienSprite;
}
I try to initialize it by:
list<Invader> *invaders = new list<Invader>();
int spacing = 10;
for (int i = 0; i < 5; i++)
{
Invader invader;
invader.Init(TOP_ALIEN, gameResources->getAlienImageTop());
invader.AlienSprite->m_X = 50 + spacing;
invaders->push_back(invader);
spacing += 50;
}
After pushing the object invader to the list, at the end the invaders list holds pointers that are not initialized. All the pointers got lost the references. I wonder why ?
The problem, I assume, is what happens in ~Invader(). Let's simplify the example a ton:
struct A {
int* p;
A() { p = new int(42); }
~A() { delete p; }
};
A just manages a pointer. When an A goes out of scope, that pointer gets deleted. Now, what happens when we do this:
list<A> objs;
{
A newA;
objs.push_back(newA);
// newA deleted here
}
// objs has one element... but its pointer has been deleted!
The problem is that copying A (which push_back() does) just performs a shallow copy: we copy our pointer. But since A manages its own memory, we need to do a deep copy. That is:
A(const A& rhs)
: p(new int(*(rhs.p)))
{ }
That way, the copied A won't double delete the same pointer. With C++11, this can be much more easily managed with just:
struct A {
std::shared_ptr<int> p;
A() { p = std::make_shared<int>(42); }
~A() = default; // this line not even necessary
};
Here, copying A will copy the shared_ptr and both copies of A will have a valid object to point to. If you can't use C++11, you can still use boost::shared_ptr<T> for all your memory management needs. And if you can't use that, then you have to write a copy constructor that does a full copy of all your pointer elements.
Or, the simplest solution, would be to just make your container have pointers:
list<A*> objs;
objs.push_back(new A);
Then the "shallow copy" is the right thing to do, and all you need to do is remember to delete everything in the container at the end.
Your list contains Invader objects. When you store them in the list, the Invader copy-constructor is called and a copy of the variable invader is stored in the list.
Unless you define a copy-constructor, it will be default simply do a shallow-copy of your object. This may not be what you want. You should write an explicit copy-constructor to make sure that the Invader is copied correctly.
Another solution would be to dynamically allocate Invader objects using the new keyword and storing pointers in the list. If you do that, be careful to make sure that you call delete on the Invader objects in the list when you are done with them.
Related
I have two classes that are essentially string classes that look like this.
The first class holds a string as a member and the second class also holds a string plus an array of pointers for the 'MenuItem' class and also a tracker.
const int MAX_NO_OF_ITEMS = 10;
class Menu; // forward declaration
class MenuItem {
char* Menuitem;
//member functions
MenuItem();
...
~MenuItem();
friend Menu;
};
class Menu {
private:
char* m_Title;
MenuItem* m_MenuItems[MAX_NO_OF_ITEMS];
int m_menuTracker;
... //other functions not shown
}
I want to be able to deep copy one Menu object to another Menu object but the way I am doing it seems do be as if it were a shallow copy when it comes to copying over the 'm_MenuItems'. I know for sure that the 'm_Title' member is getting deep copied as I am creating a 'new' char* for it but the problem arises when I am trying to copy the source 'm_MenuItems' to the destination as they end up sharing the same memory. This causes problems because when the deconstructor is called, it is called twice on the same object, causing my program to crash.
Here is my copy and assignment code:
Menu& Menu::operator=(const Menu& src) {
if (this != &src && src.m_Title != nullptr) {
delete[] m_Title;
m_Title = nullptr;
m_Title = new char[strlen(src.m_Title) + 1];
strcpy(m_Title, src.m_Title);
//if current object has menuItems, then delete to make room for src.
for (int i = 0; i < m_menuTracker; i++) {
delete m_MenuItems[i];
this->m_MenuItems[i] = nullptr;
}
This following for-loop is where my problem arises...
if (src.m_MenuItems[0] != nullptr) {
for (int i = 0; i < src.m_menuTracker; i++) {
m_MenuItems[i] = src.m_MenuItems[i];
}
this->m_menuTracker = src.m_menuTracker;
}
else
this->m_menuTracker = 0;
}
else {
this->setEmpty();
}
return *this;
}
How am I supposed to allocate a new block of memory for the destination 'm_MenuItems'?
I have an Array class written with RAII in mind (super simplified for the purpose of this example):
struct Array
{
Array(int size) {
m_size = size;
m_data = new int[m_size];
}
~Array() {
delete[] m_data;
}
int* m_data = nullptr;
int m_size = 0;
};
Then I have a function that takes a reference to an Array and does some operations on it. I use a temporary Array temp to perform the processing, because for several reasons I can't work directly with the reference. Once done, I would like to transfer the data from the temporary Array to the real one:
void function(Array& array)
{
Array temp(array.m_size * 2);
// do heavy processing on `temp`...
array.m_size = temp.m_size;
array.m_data = temp.m_data;
}
The obvious problem is that temp goes out of scope at the end of the function: its destructor is triggered, which in turn deletes the memory. This way array would contain non-existent data.
So what is the best way to "move" the ownership of data from an object to another?
What you want is move construction or move assignment for your array class, which saves you redundant copies. Also, it will help you to use std::unique_ptr which will take care of move semantics for allocated memory for you, so that you don't need to do any memory allocation directly, yourself. You will still need to pull up your sleeves and follow the "rule of zero/three/five", which in our case is the rule of five (copy & move constructor, copy & move assignment operator, destructor).
So, try:
class Array {
public:
Array(size_t size) : m_size(size) {
m_data = std::make_unique<int[]>(size);
}
Array(const Array& other) : Array(other.size) {
std::copy_n(other.m_data.get(), other.m_size, m_data.get());
}
Array(Array&& other) : m_data(nullptr) {
*this = other;
}
Array& operator=(Array&& other) {
std::swap(m_data, other.m_data);
std::swap(m_size,other.m_size);
return *this;
}
Array& operator=(const Array& other) {
m_data = std::make_unique<int[]>(other.m_size);
std::copy_n(other.m_data.get(), other.m_size, m_data.get());
return *this;
}
~Array() = default;
std::unique_ptr<int[]> m_data;
size_t m_size;
};
(Actually, it's a bad idea to have m_size and m_data public, since they're tied together and you don't want people messing with them. I would also template that class on the element type, i.e. T instead of int and use Array<int>)
Now you can implement your function in a very straightforward manner:
void function(Array& array)
{
Array temp { array }; // this uses the copy constructor
// do heavy processing on `temp`...
std::swap(array, temp); // a regular assignment would copy
}
if you insist on your example format, then you are missing a couple of things. you need to make sure that the temp array does not destroy memory reused by the non-temp array.
~Array() {
if (md_data != nullptr)
delete [] m_data;
}
and the function needs to do clean move
void function(Array& array)
{
Array temp(array.m_size * 2);
// do heavy processing on `temp`...
array.m_size = temp.m_size;
array.m_data = temp.m_data;
temp.m_data = nullptr;
temp.m_size = 0;
}
To make it more c++ like, you can do multiple things. i.e. in the array you can create member function to move the data from other array (or a constructor, or assign operator, ...)
void Array::move(Array &temp) {
m_size = temp.m_size;
temp.m_size = 0;
m_data = temp.m_data;
temp.m_data = 0;
}
in c++11 and higher you can create a move constructor and return your value from the function:
Array(Array &&temp) {
do your move here
}
Array function() {
Array temp(...);
return temp;
}
there are other ways as well.
I have a class, Somec, with a vector of pointers to items. Each item in the vector is from another class type, Myitem.
I want to make a copy function for Somec, but I am having some problems.
Also, I have a copy function for Myitem, do I have to use it in the copy function for Somec?
What I have tried so far:
class Somec {
string Name;
std::vector<Myitem*> Items;
public:
Somec(const Somec& somec); // my copy function
};
/// this the clas to my item :
class Myitem {
Itemk itemk;
public:
// ... some fuction
};
// now I want to make a copy function for Somec
Somec::Somec(const Somec& somec) {
int size = somec.Items.size();
this->Items = new (vector*) (size); // i get an error here
this->Name = somec.Name;
for(int i = 0; i < size; i++) {
*Items.at(i) = *somec.Items.at(i);
}
}
UPDATE: I made the copy function just like Remy Lebeau told me to, but when I try to test this function the code stops working. This is how I am testing it:
class Somec {
string Name;
std::vector<Myitem*> Items;
public:
Somec(const Somec& somec); // my copy function
};
Somec::Somec(const Somec& somec) { // new copy function for somec
int size = somec.Items.size();
this->Name = somec.Name;
for(int i = 0; i < size; i++) {
Items.push_back(new Myitem(*somec.Items[i]));
}
}
// create item function
void Somec::createitem(char* name, const int& Time, const int& level) {
try{
Myitem* ORitem=new Myitem(name, Time, level);
Somec::Items.push_back(ORitem);
}
catch(MemoryProblemException& error) {
throw SomecMemoryProblemException();
}
}
std::vector<Myitem*> Somec::getAllItems() const {
return Items;
}
/// this the class to my item :
class Myitem {
Itemk itemk;
public:
// ... some fuction
};
// my copy function to MYitem
Myitem::Myitem(const Myitem& item){
Myitem* currie = Myitem::clone_item();
curritem->item = itemCopy(item.item);
if (!curritem->item) {
throw itemMemoryProblemException();
return;
}
}
void testCopy() {
Somec somec("name1")
somec.createitem((char*) "item1", 30, 1, 2);
Somec temp(somec);
int x=0;
if ( std::equal(somec.getAllItems().begin() + 1, somec.getAllItems().end(), somec.getAllItems().begin()) ) {
x++;
}
ASSERT_TRUE(x==1);
}
What is my problem? I mean, I did the copy function, I think it is true. But why does the code stop working? Am I testing this in the right way?
My createitem function, I am 100% sure about it, actually.
I am just trying to add items to the the vector in Somec and check if this happened correctly. I learned that in C++, we need a copy constructor, so I wrote one, and thought about testing it since this is my first time doing one.
If you want to copy elements from the vector of the other instance to the vector of your current instance in the copy constructor, then simply do this
class Somec {
string Name;
std::vector<Myitem> Items;
public:
Somec(const Somec& somec); // my copy function
};
i.e. make the vector of values instead of pointers.
If for some reason you have to have to work with pointers, because maybe the copy constructor is deleted or something similar. Then still use this approach, but just don't copy the contents of in the copy constructor, let them get constructed and then assign them
Somec(const Somec& somec) {
this->Items.resize(somec.Items.resize());
for (std::size_t i = 0; i < somec.Items.size(); ++i) {
this->Items[i] = somec.Items[i];
}
// or simply
this->Items = somec.Items;
}
The default compiler-generated copy constructor already does exactly what your copy constructor is doing manually. So it is redundant code.
However, assuming Somec owns the items, then you do need to define a custom copy constructor, and it needs to allocate new Myitem objects and copy the existing data into them, eg:
Somec::Somec(const Somec& somec) {
this->Name = somec.Name;
std::size_t size = somec.Items.size();
this->Items.reserve(size);
for(std::size_t i = 0; i < size; i++) {
Items.push_back(new Myitem(*somec.Items[i]));
}
}
You will have to do something similar in an overriden operator= as well. You can utilize the copy constructor to help you:
Somec& Somec::operator=(const Somec& somec) {
if (&somec != this) {
Somec temp(somec);
std::swap(this->Name, temp.Name);
std::swap(this->Items, temp.Items);
}
return *this;
}
And, of course, make sure you free the owned items in the destructor:
Somec::~Somec() {
std::size_t size = somec.Items.size();
for(std::size_t i = 0; i < size; i++) {
delete Items[i];
}
}
See Rule of Three for more details about why this trio is needed.
Lets say I have the following:
int main() {
int* test = new int;
*test = 5;
int* test2 = test;
}
Then, somewhere, in some function , I deallocate memory for test2 and set it to NULL. Is there a way to set test to NULL, in the same function without passing it to the function?
EDIT: std::shared_ptr cannot be used
The shared_ptr and weak_ptr classes do exactly what you want. Since you can't use them, your best option is to re-implement just the portions of them that you need. I'm going to assume you don't need any thread safety and that you don't care about optimizations for simplicity. If you do, use the standard library.
You need a control object. It should have a pointer to the real object and two integers, one the count of strong pointers, the other the count of weak pointers. Strong pointers and weak pointers should have a pointer to the control object.
When a strong pointer is destroyed, decrement the strong pointer count. If the strong pointer count is zero, delete the object and set its pointer to NULL. If the weak pointer count is also zero, discard the control object.
When a weak pointer is destroyed, decrement the weak pointer count. If both pointers counts are zero, discard the control object.
When pointers are copied, you must bump the count. When a weak pointer is promoted to a strong pointer, bump the strong pointer count and fail the operation if it was previously zero.
That should be enough to give you the idea.
Pass the pointer be reference, since a copy would be passed to the function had you used a normal pointer, on which you can only change the pointed value, and since both pointers point to the same thing, no need to call change() on both:
#include <iostream>
void change(int*& p)
{
delete p;
p = nullptr;
}
int main()
{
int* test = new int;
*test = 5;
int* test2 = test;
std::cout << *test; //5
std::cout << *test2; //5
change(test);
}
Example
BTW, I recommend std::shared_ptr for a purpose like this, or std::unique_ptr
EDIT
The only problem above is that test2 is deleted, not pointing to nullptr, but that cannot be changed unless with smart pointers or a different function.
By default, when you pass a pointer to a function, you are passing a copy of the value:
void f(int* p) {
// p has the same value as x below, but is independent
delete p;
p = nullptr;
// p is null, but back in main 'x' still has the original value
}
int main() {
int* x = new int;
f(x);
// 'x' is unmodified and now points to a deleted block of memory
}
Your options are to pass the pointer by reference or pass a pointer to the pointer:
#include <iostream>
void by_pointer(int** p) {
delete *p;
*p = nullptr;
}
void by_reference(int*& p) {
delete p;
p = nullptr;
}
int main() {
int* x = new int;
by_pointer(&x);
std::cout << (void*)x << "\n"; // outputs null
int* y = new int;
by_reference(y);
std::cout << (void*)y << "\n"; // outputs null
}
If you really want this (though I'd strongly suggest you to reconsider your design), then the following might work for you:
We wrap the pointer in a structure/class to be able to "hook" us on construction and destruction of such pointers:
template<typename T>
struct pointer {
Since when freeing the stored value, we also need to modify all pointers that still point to it, we need to keep track of them somehow. I'd say just store them alongside the value:
struct boxing {
T value;
std::set<pointer<T> *> references;
};
boxing * box;
Next comes constructing a pointer. I simplified here. You might want to add perfect forwarding, a possibility to construct a "null pointer", and so on ...
pointer(T value) : box(new boxing{value}) {
add_myself();
}
As you see, we "add ourselves" (to the set of references). When the pointer is destructed, we need to remove ourselves from that set again:
~pointer() {
remove_myself();
}
When being copy constructed, we just use the box from the original and add ourselves:
pointer(pointer const & p) : box(p.box) {
add_myself();
}
When being copy assigned to, we first need to remove ourselves from the current box, use the box of the original and add ourselves:
pointer & operator=(pointer const & p) {
remove_myself();
box = p.box;
add_myself();
}
I'm lazy. Implement move construction / assignment yourself ;)
pointer(pointer &&) = delete;
pointer & operator=(pointer &&) = delete;
We want to be able to use the pointer, so we add a conversion operator to a raw pointer:
operator T*(void) {
return box ? &(box->value) : nullptr;
}
Finally, freeing a pointer. We set all box members of the current pointers in the references set to nullptr (this includes ourself, thus the additional pointer b), and then delete the box:
void free() {
boxing * b = box;
for (pointer * p : b->references) {
p->box = nullptr;
}
delete b;
}
Oh, and last but not least, adding and removing ourselves:
private:
void remove_myself() {
if (box == nullptr) return;
box->references.erase(this);
if (box->references.size() == 0) {
delete box;
}
}
void add_myself() {
if (box == nullptr) return;
box->references.insert(this);
}
};
Some function. Note that I pass by value to force another copy construction:
void foo(pointer<int> p) {
p.free();
}
Two pointers, pointing to the same boxed value:
int main(int, char **) {
pointer<int> a{21};
pointer<int> b = a;
*b = 42;
std::cout << *a << std::endl;
foo(a);
std::cout << "a is " << ((a == nullptr) ? "null" : "non-null") << std::endl;
return 0;
}
Above example on ideone.
The idea of shared controllers of a uniquely-owned object is of course horrid (for reasons that will become clear).
Nevertheless, it can be done:
template<class T, class Deleter = std::default_delete<T>>
struct shared_unique
{
struct control_block
{
control_block(Deleter del, T* p) : del_(std::move(del)), ptr_(p), refs_(1) {}
Deleter del_;
T* ptr_;
std::size_t refs_;
void addref()
{
++refs_;
}
void release()
{
if (--refs_ == 0)
delete this;
}
~control_block() {
if (ptr_)
del_(ptr_);
}
};
control_block* ctrl_;
shared_unique(T* p = nullptr, Deleter del = Deleter()) : ctrl_(new control_block(std::move(del), p)) {}
shared_unique(shared_unique const& r) : ctrl_(r.ctrl_) { ctrl_->addref(); }
shared_unique& operator=(shared_unique const& r)
{
auto tmp = r;
swap(r);
return *this;
}
shared_unique(shared_unique&& r) : ctrl_(r.ctrl_) { r.ctrl_ = nullptr; }
shared_unique& operator=(shared_unique&& r)
{
auto tmp = std::move(r);
swap(tmp);
return *this;
}
~shared_unique()
{
ctrl_->release();
}
void swap(shared_unique& r) noexcept
{
std::swap(ctrl_, r.ctrl_);
}
void reset(T* p = nullptr)
{
std::swap(ctrl_->ptr_, p);
delete p;
}
T* get() const {
return ctrl_->ptr_;
}
};
int main()
{
shared_unique<int> su1(new int(5));
assert( su1.get() );
assert( *(su1.get()) == 5 );
shared_unique<int> su2 = su1;
assert( su2.get() );
assert( *(su2.get()) == 5 );
su1.reset();
assert( su1.get() == nullptr );
assert( su2.get() == nullptr );
}
The problem is that it is impossible to make this arrangement thread-safe, unless you provide some kind of 'lock' mechanism to keep the pointed-to object alive while it's being accessed.
If you want to know when an object has been destroyed, it's probably better to have it (or its smart pointer) emit a signal when this happens and have the interested observers listen on the slot (or similar).
I'm having trouble transferring some data contained in a vector between my functions. The situation is as follows:
void generateObjects(std::vector<MyClass> &objects)
{
objects.clear();
//Fill objects vector
std::vector<MyClass> p;
//This 4-line pattern is repeated a number of times to generate all objects and store them in variable 'objects'
p.clear();
generateSomeOfTheObjects(p); //p is again passed by ref. in/out parameter
for(uint j = 0; j < p.size(); p++){
objects.push_back(p[j]);
}
//Print some members of the objects - works fine
for(uint i = 0; i < objects.size(); i++){
printf("%f ",objects[i].mymember->myElm);
}
}
int main()
{
std::vector<MyClass> objects;
generateObjects(objects);
//Print size of vector - size is correct it is the same as it is in generateObjects func
printf("%lu\n",objects.size());
//Again print members of the objects - some members are retained after the function call, some are lost.
//The one below doesn't work, mymember is a pointer to another object and its member myElm seems not initialized.
for(uint i = 0; i < objects.size(); i++){
printf("%f ",objects[i].mymember->myElm);
}
//Here I need to pass the objects to another read-only function
...
}
I have searched the internet for similar cases and actually found many, but I couldn't apply the same fixes to my code. I'm trying to reach a member of an object pointed to by a member of a MyClass instance (objects[i].mymember->myElm) What possibly am I missing here?
Probably the error lies in the implementation of MyClass. I'd say that this class contains some pointer that is initialized with the address of a local variable, so when you return from some of the functions that pointer points to a destroyed object.
That would undefined behavior but it may work by chance. When you return from the first function, the stack memory is finally overwritten and your data is lost.
UPDATE: Thanks to the insight by #chris in the comments below, the most likely reason is that your MyClass does not have a copy constructor, but it does have a pointer member.
Something like this:
class MyClass
{
public:
Member *mymember;
MyClass()
{
mymember = new Member;
}
~MyClass()
{
delete mymember;
}
};
Now what happens if you use the compiler generated default copy constructor (or the copy operator)?
void foo()
{
MyClass a;
{
MyClass b(a);
}
//a.mymember is no longer valid
}
Both a and b share the same pointer mymember, so when one of them is destroyed, the mymember is deleted and the other one holds a dangling pointer.
That's why we have the rule of three. It states:
Whenever you define a non-default destructor, you most likely will want also a non-default copy-constructor and a non-default copy-operator.
Now you have to decide if you want to share the ownership of the mymember or if you want to copy it. The first one is best done with smart pointers (shared_ptr) and the second one with deep copy.
For example, deep copy:
class MyClass
{
public:
Member *mymember;
MyClass()
{
mymember = new Member;
}
MyClass(const MyClass &c)
{
mymember = new Member(c.mymember);
}
MyClass &operator=(const MyClass &c)
{
if (this != &c) //be aware of self-copy
{
delete mymember;
mymember = new Member(c.mymember);
}
return *this;
}
~MyClass()
{
delete mymember;
}
};
And with shared pointers:
class MyClass
{
public:
std::shared_ptr<Member> mymember; //or boost::shared_ptr if old compiler
MyClass()
:mymember(new Member)
{
}
//no custom-made destructor -> no rule of 3
};
Perhaps unrelated to you question, but this:
void generateObjects(std::vector<MyClass> &objects)
{
objects.clear();
std::vector<MyClass> p;
p.clear();
generateSomeOfTheObjects(p);
for(uint j = 0; j < p.size(); p++){
objects.push_back(p[j]);
}
for(uint i = 0; i < objects.size(); i++){
printf("%f ",objects[i].mymember->myElm);
}
}
Is the same as this:
void generateObjects(std::vector<MyClass> &objects)
{
objects.clear();
generateSomeOfTheObjects(objects);
std::reverse(objects.begin(), objects.end());
for(uint i = 0; i < objects.size(); i++) {
printf("%f ",objects[i].mymember->myElm);
}
}
You copy issues, as #rodrigo mentioned, is that you are not doing deep copies with your copy constructors.