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.
Related
I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I have a beginner's knowledge in C, so I know that I can create a pointer to the object, and make a vector of pointers. e.g. vector<Object *>. However, it seems as if pointers are discouraged in C++, and references are preferred. Yet, I cannot make a vector of references.
I wish to use only the standard libraries, so boost is off limits to me.
I heard of smart pointers. However, it appears as if there are multiple types of smart pointers. Would it not be overkill for this purpose? If smart pointers are indeed the answer, then how do I determine which one to use?
So my question is: What is the standard practice for creating a vector of references/pointers to objects?
In other words, would like the below (pseudo-)code to work.
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
class Object
{
public:
int field;
};
vector<Object> addToVector(Object &o)
{
vector<Object> v;
v.push_back(o);
v[0].field = 3; // I want this to set o.field to 3.
return v;
}
int main()
{
Object one;
one.field = 1;
cout << one.field << endl; // 1 as expected
Object &refone = one;
refone.field = 2;
cout << one.field << endl; // 2 as expected
vector<Object> v = addToVector(one);
cout << v[0].field << endl; // 3 as expected
cout << one.field << endl; // I want to get 3 here as well, as opposed to 2.
return 0;
}
I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I'm almost certain that this is not what you want or "should" want. Forgive me that direct opening of my answer, but unless you have a very good reason to do this, you probably don't want to do it.
For that - a vector with references - to work you must guarantee that the referenced objects won't get moved nor destructed while you hold references to them. If you have them in a vector, make sure that vector isn't resized. If you have them on the stack like in your example, then don't let the vector of references or a copy of it leave that stack frame. If you want to store them in some container, use a std::list (it's iterators - pointers basically - don't get invalidated when inserting or removing elements).
You already noticed that you cannot have a vector of "real" references. The reason therefore is that references aren't assignable. Consider following code:
int a = 42;
int b = 21;
int & x = a; // initialisation only way to bind to something
int & y = b;
x = y;
b = 0;
After that, the value you obtain from x will be 21, because the assignment didn't change the reference (to be bound to b) but the referenced object, a. But a std::vector explicitly requires this.
You could now set out and write an wrapper around a pointer like ...
template<typename T>
struct my_ref {
T * target;
// don't let one construct a my_ref without valid object to reference to
my_ref(T & t) : target(&t) {}
// implicit conversion into an real reference
operator T &(void) {
return *target;
}
// default assignment works as expected with pointers
my_ref & operator=(my_ref const &) = default;
// a moved from reference doesn't make sense, it would be invalid
my_ref & operator=(my_ref &&) = delete;
my_ref(my_ref &&) = delete;
// ...
};
... but this is pretty pointless since std::reference_wrapper already provides exactly that:
int main (int, char**) {
int object = 21; // half of the answer
vector<reference_wrapper<int>> v;
v.push_back(object);
v[0].get() = 42; // assignment needs explicit conversion of lhs to a real reference
cout << "the answer is " << object << endl;
return 0;
}
(Example live here)
Now one could argue why using a wrapper around a pointer like std::reference_wrapper when one could also directly use a pointer. IMO a pointer, having the ability to be nullptr, changes the semantics of the code: When you have a raw pointer, it could be invalid. Sure, you can just assume that it's not, or put it somewhere in comments, but in the end you then rely on something that's not guaranteed by the code (and this behaviour normally leads to bugs).
If an element of your vector could "reference" an object or be invalid, then still raw pointers aren't the first choice (for me): When you use an element from your vector which is valid, then the object referenced by it is actually referenced from multiple places on your code; it's shared. The "main" reference to the object then should be a std::shared_ptr and the elements of your vector std::weak_ptrs. You can then (thread safe) acquire a valid "reference" (a shared pointer) when you need to and drop it when done:
auto object = make_shared<int>(42);
vector<weak_ptr<int>> v;
v.push_back (object);
// ... somewhere later, potentially on a different thread
if (auto ref = v[0].lock()) {
// noone "steals" the object now while it's used here
}
// let them do what they want with the object, we're done with it ...
Finally, please take my answer with a grain of salt, much of it is based on my opinion (and experience) and might not count as "standard practice".
I'm working on a C++ project and I wonder if it's possible to store the same object in two different vector. I know how to deal with it in C with pointer, so you reference the same object to both table, but I'm little bit confused in C++.
If I create an object and I store it in vector a and in vector b. Do C++ copy the object or it's the same on both vector and if I modify one, the other is modified too ? In the second case, does it take more place to store it twice (for accessibility issues) or it's not a good way to deal with it ?
Thanks.
Cppreference is a great place to check exactly this type of questions. Let me quote the relevant parts of the link:
void push_back( const T& value );
void push_back( T&& value );
Appends the given element value to the end of the container.
1) The new element is initialized as a copy of value.
2) value is moved into the new element.
So yes, storing the same element twice in two vectors will cause it to get copied twice. You should use std::vector<T*> if you don't want to waste memory. And as always, you should also consider smart pointers (std::shared_ptr / std::weak_ptr) instead of naked pointers.
It's similar to C, really.
If what you have is a vector<object>, then you'll be working with different objects.
On the other hand, a vector<object*> ensures that you'll only be storing pointers to your objects and then having multiple vectors containg the same object or objects is not an issue.
You might also consider using std::shared_ptr and std::weak_ptr to simplify memory management when working with pointers in C++.
When you insert an object into a std::vector a copy of it is made:
Foo a;
std::vector<Foo> vec1;
std::vector<Foo> vec2;
vec1.push_back(a); //copy made
vec2.push_back(b); //copy made
If you do not want a copy, you can either use pointers or std::reference_wrapper (you can't use references as they don't fulfil constraints on container value types):
Foo a;
std::vector<Foo*> vec1;
std::vector<std::reference_wrapper<Foo>> vec2;
vec1.push_back(&a); //no copy
vec2.push_back(std::ref(b)); //no copy
Of course, now no need to ensure that the lifetime of a is no shorter than that of the vectors, otherwise you're on the fast-track to undefined behaviour.
You could also use std::shared_ptr which will ensure that your object is destructed when there are no more references to it:
std::shared_ptr<Foo> a = std::make_shared<Foo>();
std::vector<std::shared_ptr<Foo>> vec1;
std::vector<std::shared_ptr<Foo>> vec2;
vec1.push_back(a); //reference count incremented
vec2.push_back(a); //reference count incremented
I made a simple example for you:
class SomeObject { public: int a; };
int main()
{
SomeObject some_object;
some_object.a = 1;
//Copies are made
std::vector<SomeObject> foo;
foo.push_back(some_object);
std::vector<SomeObject> bar;
bar.push_back(some_object);
foo.at(0).a = 2;
bar.at(0).a = 3;
std::cout << foo.at(0).a << ' ' << bar.at(0).a;
//Refers to the same object
std::vector<SomeObject*> baz;
baz.push_back(&some_object);
std::vector<SomeObject*> foobar;
foobar.push_back(&some_object);
baz.at(0)->a = 4;
foobar.at(0)->a = 5;
std::cout << ' ' << baz.at(0)->a << ' ' << foobar.at(0)->a;
return 0;
}
Outputs:
2 3 5 5
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.
If I create an object on the stack and push it into a list, then the object loses scope (outside of the for loop in the example below) will the object still exist in the list? If the list still holds the object, is that data now invalid/possibly corrupt?
Please let me know, and please explain the reasoning..
Thanks,
jbu
class SomeObject{
public:
AnotherObject x;
}
//And then...
void someMethod()
{
std::list<SomeObject> my_list;
for(int i = 0; i < SOME_NUMBER; i++)
{
SomeObject tmp;
my_list.push_back(tmp);
//after the for loop iteration, tmp loses scope
}
my_list.front(); //at this point will my_list be full of valid SomeObjects or will the SomeObjects no longer be valid, even if they still point to dirty data
}
EDIT: so what if it were a std::list<SomeObject*> my_list; instead of list...in that case would it be invalid?
The standard containers make a copy of the object so the list is still ok in your example.
All containers make a copy of what they store. It's a requirement that an object be copy-constructible and assignable, if it is to be used in a container.
So yes, vector, list, etc. all make a copy of your object.
An even shorter example:
struct foo {};
std::vector<foo> v;
v.push_back(foo());
// makes a copy of the temporary, which dies at the semicolon.
If it didn't make a copy, the above code would be bad.
The following code is not ok:
struct foo {};
std::vector<foo*> v;
{
foo f;
v.push_back(&f); // fine, but...
} // ...now f stops existing and...
v.front(); // ...points to a non-existent object.
Yes, it's valid. push_back makes a copy.
With all STL containers (lists, vectors, maps, everything), the containers make a copy of what you add to the containers so, so long as what you add isn't a pointer or reference, you're safe.
If you write your own containers though, you have to be careful how you do things, since there's nothing stopping you from writing a type of container that stores references -- it would just be a nasty surprise to anyone that thought it worked like a standard container.
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).