It should be a simple question, but for the life of me I can't finda solution online.
Simply put, creating an object and adding it to a list of pointers doesn't work for me - as soon as I try access the item in the list in a different method to where it was created, it gives an access violation.
So two questions:
1: What's the best way of doing this?
2: Subsequently, if it's not using pointer lists, what's the best way of removing from the list?
int main( int argc, const char* argv[] )
{
std::list<testClass*> list;
addClass(list);
std::cout << list.front()->a; //item added to list now longer accessible
}
void addClass(std::list<testClass*> list)
{
testClass* c = new testClass();
c->a = 1; c->b = 2;
list.push_back(c); //item still accessible here
}
class testClass
{
public:
int a;
int b;
};
You need to pass your list by reference, you are passing by value here and so it is making a copy of the container and working on that copy:
void addClass(std::list<testClass*> list)
If you modify it like so it should work as you want:
void addClass(std::list<testClass*> &list)
A first macroscopic error is that addClass shold take a std::list<testClass*> & so that it operates on the list contained in main, an not on a local copy.
After that, the entire design has to be better focalized:
Since testClass is not polymorphic (there is nothing virtual in it) what is the point to allocate them dynamically? It will probably be easier to let them contained as value directly in the list itself, havig a std::list<testClass>.
Or ... if you need dynamic allocation, you also have to consider deallocation, or you wil leak memory: if the list cotains pointers, it will destroy the pointer, not what they point-to.
So now, let's follow the two tracks:
Treating objects as values
You need a way to construct a testClass object from given values.
class testClass
{
public:
testClass(int a_, int b_)
:a(a_), b(b_)
{}
int a;
int b;
};
and now you can
void addClass(std::list<testClass>& list)
{
list.emplace_back(1,2);
}
and
int main()
{
std::list<testClass> list;
addClass(list);
std::cout << list.front().a;
}
Note how some * disappered!
Treating objects dinamically
Ok creating with new, but you have to take care of deletion.
One way is delete the pointed from list: just before the } in main...
for(auto p : list) delete p;
this will run across the list and call delete for each of the pointers, thus deallocating (and destroying) the object you allocated with new.
NOTE: This does not make the list empty: the list still contains the pointers, they simply point to invalid address. The pointers will be deallocated by the list at the exit from main
Another way is not to use plain pointers but smart pointer that delete themselves the content when they are destroyed.
This requires an std::list<std::unique_ptr<testClass> > as a container, so that you can
void addClass(std::list<std::unique_ptr<testClass> >& list)
{
list.emplace_back(new testClass(1,2));
}
Now, when main exits, the list gets destroyed with its own elements (the smart pointer) tha in turn will delete the new allocated objects.
Related
I have a function used to initialize array in C++. after the initialization, main can not access the data in the array. Don't know why. Any help?
void testArray(int *listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}// end testArray
void main()
{
int *list;
testArray(list);
cout<<list[0]<<list[1]<<endl; // this gives some random output
} // end main
This is because the pointer is passed by value. The argument to the function is copied, and the first line of your function replaces the local copy of the pointer with the result of the new expression. The original copy of your pointer, back in main(), is unaffected by this.
You can "fix" this by either passing the pointer by reference:
void testArray(int*& listPtr)
{
listPtr = new int[2];
// ...
}
int main()
{
int* list = 0;
testArray(list);
// ...
delete list;
return 0;
}
or by passing a pointer to the pointer:
void testArray(int** listPtr)
{
*listPtr = new int[2];
// ...
}
int main()
{
int* list = 0;
testArray(&list);
// ...
delete list;
return 0;
}
or, better still, by using a C++ standard library container that provides value semantics (in conjunction with a reference argument):
void testVec(std::vector<int>& list)
{
list.resize(2);
list[0] = 0;
list[1] = 1;
}
int main()
{
std::vector<int> list;
testVec(list);
// ...
return 0;
}
Analogy time:
The problem arises because a pointer is a separate entity (object) that points to some other object. Pointers can be copied just as regular objects can, and there is no special consideration given to them to make sure that the thing they point to is updated to reflect any change made to the pointer. A reference is a different beast entirely. Once a reference has been bound to some object, it is (to all intents and purposes) indistinguishable from the object itself; any operation on the reference is an operation on the underlying object. You can think of it as though you possess a cat named Fluffy, and you let your friend borrow Fluffy; but your friend calls her Buffy. It's the same cat, and if your friend trims her claws, the next time you see Fluffy, she'll have trimmed claws.
For the pointer example, you have Fluffy, and you give your friend a note with Fluffy's address written on it. Your friend goes and gets a new cat, and writes the new cat's address on top of the note you gave them. Now, when your friend trims the claws of the new cat, nothing at all happens to Fluffy. The note just allows your friend to go to the place where Fluffy lives; right up to the point where your friend overwrites the note with the address of some other cat.
References make it much easier to reason about the behaviour of your code, and should be preferred in almost all situations.
You need pass by reference, so that the change to the pointer listPtr itself can be passed out to the outter variable. Remember, you are changing the value of "the pointer itself", which is invisible to the caller if pass by value.
void testArray(int * &listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}// end testArray
You need to use pass by reference, so that listPtr get updated while initializing it in testarray function.
To do that do the following -
void testArray(int * &listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}
If you are confused about the above solution you can simply declare and initialize this one globally.
I create a vector A and want to copy to a vector B in another class by using below method, is it a correct way? The vector A may be destroyed! I searched in google, but not found the good solution and meaningful explanation. Thanks everyone
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Yes and no, you are passing the vector by value:
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Wich means that listBtn is a copy of vector A (asuming we are calling vector A the one passed as parameter of StateInit), if you delete vector A, vector B will still have the collection of pointers and they will be valid since the destruction of a vector of pointers doesnt delete the pointed objects because it cant possible now how (should it call, delete, delete[], free?).
Do keep in mind that if you modify/delete one of the elements from vector A (using the pointers on the vector), that element will be modified in vector B (since its a pointer to the same element).
Im not sure what is your intend with this, but if you want to copy the whole vector, you should implement a clone mechanism for the objects and then copy them using transform:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
Then just:
void StateInit(vector<CButton*> listBtn)
{
transform(listBtn.begin(), listBtn.end(), back_inserter(_m_pListBtn), cloneFunctor());
};
IF your intention is not to clone it but to share the pointers you should pass the vector as pointer or reference:
void StateInit(const vector<CButton*>& listBtn)
{
_m_pListBtn = listBtn;
};
A better way is to iterate on the new vector and push_back the elements to your vector.
See example code: std::vector::begin
I'm a long-time reader, and first-time poster... I've searched long and hard to find an answer to something that's really boggling my mind right now. I must be missing something, as I believe this should work...
I'm trying to create a datatable class that will contain it's own copies of the objects passed to it. I've decided to use std::map's to contain this data. See the example code below:
typedef std::map <std::string, myVar *> myVarContainer;
class myObj
{
public:
myObj(void);
virtual ~myObj(void);
void setVar(std::string Key, myVar & Var);
myVar * getVar(std::string Key);
void release()
{
for (myVarContainer::iterator i = VarContainer->begin(); i != VarContainer->end(); ++i)
{
delete (i->second);
}
VarContainer->clear();
};
myVarContainer * VarContainer;
};
typedef std::map <myVar, myObj *> myRow;
class myTable
{
public:
myTable(void);
virtual ~myTable(void);
void addDataPoint(myVar RowID, myVar ColID, myObj * Data)
{
std::map <myVar, myRow *>::iterator i = m_Rows->find(RowID);
if (i == m_Rows->end())
{
m_Rows->insert(make_pair(RowID, new myRow()));
}
i = m_Rows->find(RowID);
// i thought the below line would be creating a copy of the data?
// I thought this logic went:
// 1. create a new object copied from the value of 'Data'
// 2. return a pointer to this object and pair with the 'colID'
// 3. make this into a pair and insert into the main map
i->second->insert(make_pair(ColID, new myObj(*Data)));
};
protected:
std::map <myVar, myRow *> * m_Rows;
}
int main()
{
myVar a, b, c, d;
myObj * o = new myObj();
o->setVar("test", a);
o->setVar("test2", b);
myTable * tab = new myTable();
myVar x1, y1, x2;
tab->addDataPoint(y1, x1, o);
o->release(); // this clears out both 'o' and the values in 'tab'!?!?
//at this point tab has no data in its object at y1,x1???
o->setVar("test3", c);
o->setVar("test4", d);
tab->addDataPoint(y1, x2, o);
}
What I'm noticing is that my data is deleted too early. I believe I've missed something... I had thought I was creating a copy of the data referenced by the pointer and then storing a newly instance'd pointer in my map... Any thoughts? I appreciate any help!
So one of the problems that using (owning) raw pointers in containers is that you need to manually delete the instances yourself. I presume that myObj::~myObj does just that (iterates the container deleting all elements before deleting the container itself).
The line:
i->second->insert(make_pair(ColID, new myObj(*Data)));
Is copy constructing a myObj from Data.
Unfortunately, because you are not defining a copy constructor for myObj the compiler will generate one for you which will just copy the pointer to the VarContainer member. It won't create a new copy of the map or anything that it refers to internally. Once a copy is created you then have two instances which both point to the same container and both instances think that they own it. When the first one gets destructed it will seem to ok but actually leaves the other instance pointing to freed memory. As soon as the longest lived instance tries to do anything using this container pointer something bad will happen.
You could fix this by storing the maps by value and not by pointer:
typedef std::map<std::string, myVar> myVarContainer;
typedef std::map<myVar, myObj> myRow;
Also change myObj::VarContainer to be a non-allocated member. This means that everything now gets copied correctly and a copy will not reference anything from the original.
Note that you can also use smart pointers (such as std::shared_ptr) instead of raw pointers but you will still need to be careful with that as, although copying would be safe, they share data with the original which might not be what you expect.
You should take a look at the following:
http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
It seems that you are indeed creating a copy of the object, but then when you release(), you are releasing the VarContainer (deleting all items and using clear()), so the copy you created before (with a copy of the pointer, not the actual container) is left with a pointer to an empty container.
does the function set::insert saves a pointer to the element or a copy of it. meaning, can I do the following code, or I have to make sure that the pointers are not deleted?
int *a;
*a=new int(1);
set<int> _set;
_set.insert (*a);
delete a;
*a=new int(2);
_set.insert (*a);
delete a;
I gave the example with int, but my real program uses classes that I created.
All STL containers store a copy of the inserted data. Look here in section "Description" in the third paragraph: A Container (and std::set models a Container) owns its elements. And for more details look at the following footnote [1]. In particular for the std::set look here under the section "Type requirements". The Key must be Assignable.
Apart from that you can test this easily:
struct tester {
tester(int value) : value(value) { }
tester(const tester& t) : value(t.value) {
std::cout << "Copy construction!" << std::endl;
}
int value;
};
// In order to use tester with a set:
bool operator < (const tester& t, const tester& t2) {
return t.value < t2.value;
}
int main() {
tester t(2);
std::vector<tester> v;
v.push_back(t);
std::set<tester> s;
s.insert(t);
}
You'll always see Copy construction!.
If you really want to store something like a reference to an object you either can store pointers to these objects:
tester* t = new tester(10);
{
std::set<tester*> s;
s.insert(t);
// do something awesome with s
} // here s goes out of scope just as well the contained objects
// i.e. the *pointers* to tester objects. The referenced objects
// still exist and thus we must delete them at the end of the day:
delete t;
But in this case you have to take care of deleting the objects correctly and this is sometimes very difficult. For example exceptions can change the path of execution dramatically and you never reach the right delete.
Or you can use smart pointers like boost::shared_ptr:
{
std::set< boost::shared_ptr<tester> > s;
s.insert(boost::shared_ptr<tester>(new tester(20)));
// do something awesome with your set
} // here s goes out of scope and destructs all its contents,
// i.e. the smart_ptr<tester> objects. But this doesn't mean
// the referenced objects will be deleted.
Now the smart pointers takes care for you and delete their referenced objects at the right time. If you copied one of the inserted smart pointers and transfered it somewhere else the commonly referenced object won't be delete until the last smart pointer referencing this object goes out of scope.
Oh and by the way: Never use std::auto_ptrs as elements in the standard containers. Their strange copy semantics aren't compatible with the way the containers are storing and managing their data and how the standard algorithms are manipulating them. I'm sure there are many questions here on StackOverflow concerning this precarious issue.
std::set will copy the element you insert.
You are saving pointers into the set.
The object pointed at by the pointer is not copied.
Thus after calling delete the pointer in the set is invalid.
Note: You probably want to just save integers.
int a(1);
set<int> s;
s.insert(a); // pushes 1 into the set
s.insert(2); // pushes 2 into the set.
Couple of other notes:
Be careful with underscores at the beginning of identifier names.
Use smart pointers to hold pointers.
Ptr:
std::auto_ptr<int> a(new int(1));
set<int*> s;
s.insert(a.release());
// Note. Set now holds a RAW pointer that you should delete before the set goes away.
// Or convert into a boost::ptr_set<int> so it takes ownership of the pointer.
int *a;
*a=new int(1);
This code is wrong because you try to use the value stored at address a which is a garbage.
And, every stl containers copy elements unless you use move semantics with insert() and push_back() taking rvalue references in C++0x.
NOTE: THIS IS NOT HOMEWORK IT IS FROM A PRACTICE EXAM GIVEN TO US BY OUR PROFESSORS TO HELP US PREPARE FOR OUR EXAM
I'm currently studying for a programming exam. On one of the sample tests they gave us we have the following question:
Suppose you have been given a templated Container that holds an unordered collection of objects.
template <typename T>
class Container {
public:
void insert(T *op);
// EFFECTS: inserts the object pointed to by op into
// the container
T *remove();
// EFFECTS: removes an object from the Container, and
// returns a pointer to it. Returns NULL if no
// objects remain in the Container.
// Note: the implementation can choose which
// object to return if more than one exists.
Container(); // ctor
Container(const Container &l); // copy ctor
Container &operator=(const Container &l); // assignment
~Container(); // dtor
private:
...
};
Note that this is the interface only; the implementation details have been left out for brevity.
However, you may assume that the implementation is node based; a linked collection of nodes
hold objects.
You suspect that the implementation of the destructor does not satisfy the Conservation Rule of the At-Most-Once invariant, and is leaking memory instead. Write an acceptance test (similar to those in Project 4) to check for this condition. You must supply a suitable contained type, and a main that performs the test.
Note that you cannot depend on any behavior that the language leaves undefined, you may not
assume that you have the altnew allocator from Project 5 available to you, and you may not
override the delete operator. Hint: you are allowed to use a global variable.
I though something like:
#include <iostream>
using namespace std;
int *p = NULL;
void leak() {
int *num = new int(5);
p = num;
delete num;
}
int main() {
if ((*p = 6)) {
cout << "Memory leak\n";
} else {
cout << "No Leak\n";
}
}
The basic idea behind this is I though I couldn't write to a space of memory that I hadn't allocated. In compiling this test code though it works just fine so apparently you can. Any ideas on how to write such a test case though?
When you say:
void leak() {
int *num = new int(5);
p = num;
delete num;
}
there is no memory leak. There is however, a dangling pointer (p) which will cause undefned behaviour if dereferenced.
What if you create a class to use as the template parameter that will add 1 to a global variable in it's constructor and decrease that same global variable by 1 in it's destructor.
Then you can perform whatever tests you want on the container (create it, fill it and empty it, delete it, etc) and check for memory leaks by checking that the global variable is 0 after the container has been destroyed.
You could use an element class like this one, which counts it's instances:
class InstCounter {
public:
static int counter;
InstCounter() { counter++; }
~InstCounter() { counter--; }
};
int InstCounter::counter = 0;
int main(int argc, char** argv)
{
{ Container<InstCounter> c;
// insert elements...
c.insert(new InstCounter);
} // calls dtor of c
if (InstCounter::counter > 0)
std::cout << "Container is leaking." << std::endl;
return 0;
}
I'm not sure what is listed in Project 4 and Project 5, but I think the way to do this is to assign a global pointer (as per the hint) to the object that you insert in the container. If you then destroy the container, it should destroy the objects within it, and that global pointer should now be null.
You can increment an integer global variable in the T constructor, and decrement it in the T destructor: doing this will tell you whether T instances are being destroyed by the container. The acceptance test can allocate a few T instances into a Container instance, destroy the Container, and test whether that destroyed the T instances (i.e. whether the T destructors were invoked).
Without overriding the delete operator I don't see an easy way to tell whether the container is not only destroying T instances but also releasing the memory which the T instances occupy: but if it is destroying T instances (which you can test as mentioned in the first paragraph above) then you might like to hope that it's probably also releasing the memory occupied by each instance.
I'd use a contained type that keeps a reference count. When you insert the item in the container, the reference count should be incremented. When you destroy the container, it should be decremented back to its starting value. The reference count could be held in either a global variable (as suggested) or a static variable inside the class (I'd normally use the latter, but it is slightly more complex).