Stl Containers with Reference to Objects

STL containers with reference to objects

Sadly no, it won't compile (with stlport at least). But the alternative, which is to store pointers to your objects in the container, will compile perfectly fine.

This will leave you with a bit of extra syntactic noise around your code - you'll have to new things in order to insert them into your container.

std::list<class_type*> l;
l.push_back(new class_type);

However though the objects now won't be copied, they also won't be automatically cleaned up for you when the list is destructed. Smart pointers will solve this for you, but at the cost of even more syntactic noise. And since you can't put std::auto_ptr's in standard containers because they can't be copied, you have to use their slightly heavier-weight boost cousins, shared pointers.

std::list<boost::shared_ptr<class_type> > l;
l.push_back(boost::shared_ptr<class_type>(new class_type));

Shared pointed do incur some extra overhead, but it is minimal.

stl container of references C++11

Yes, the requirements are less strict now. However, right below the part you're referencing, the linked documentation clearly states that:

The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type is a complete type and meets the requirements of Erasable, but many member functions impose stricter requirements. (since C++11)

References don't meet the requirements of Erasable, therefore they still can't work.

C++ STL Containers and references

You can use a reference to assign to the object - by making the loop variable o a reference:

cout << "Increnting ... " << endl;
for (MyObject &o : oset) o.value += 1000;

* EDIT *

But because set is an ordered container, it returns const iterators.
So if you need to amend a set perhaps you should consider using another container instead. Perhaps a map?

But if you really have to change a set - don't do like the code below. It makes valgrind very upset, as Matthieu has pointed out. Why you can't go around erasing elements in a container whilst iterating through that container. Such madness leads to Undefined Behavior.

// ===== ATTENTION - NASTY CODE ALERT !! ========**
for (MyObject &o : oset)
{
MyObject oNew = o;
oNew.value += 1000;
oset.erase(o);
oset.insert(oNew);
}
// =============================================**

A safer solution

would be to create another set, copy the original set (whilst applying the required changes), then swap the new set to the old one.

Here transform applies the lambda function over the entire set, and stores the results in the new nset set. inserter creates an insertion iterator for the nset container, inserting from nset.begin(). The final transform parameter - the lambda - takes an original set object and adds 1000 to it, returning the new object. Once the transform creates the new set, swap then places the new objects in the original container.

set<MyObject> nset;
transform(oset.begin(), oset.end(), inserter(nset, nset.begin()),
[](const MyObject &o) { return MyObject (o.value+1000); });
oset.swap(nset);

See this question on set updates for more info.

Lifecycle of objects passed by reference to STL containers

As far as I'm aware, STL containers
aren't meant to copy the objects which
they contain

Okay, let's stop right there. STL containers do copy their contents, frequently. They copy them when they're inserted, they copy them when the container is resized either automatically or explicitly, and they copy them when the container itself is copied. Lots and lots of copying.

I'm not sure where you got the idea that STL containers don't copy their contents. The only thing that I can think of that's even close is that if you insert a pointer into an STL container, it will copy the pointer itself but not the pointed-to data.

Also, there are no references involved in your code whatsoever, so I'm puzzled as to what the title of this question refers to.

Do standard library containers structures store copies or references?

  1. Does STL structures stores copies or references?

C++ standard containers are non-instrusive containers

and as such they have the following properties:

Object doesn't "know" and contain details about the container in which is to be stored. Example:


struct Node
{
T data;
}

1. Pros:

  • does not containe additional information regarding the container integration.
  • object's lifetime managed by the container. (less complex.)

2. Cons:

  • store copies of values passed by the user. (inplace emplace construction possible.)
  • an object can belong only to one container. (or the contaier should store pointers to objects.)
  • overhead on storing copies. (bookkeeping on each allocation.)
  • can't store derived object and still maintain its original type. (slicing - looses polymorphism.)

Thus, the answer to your question is - they store copies.


  1. Is there any way to avoid this catastrophic end, other than create just containers of pointers?

As far as I know, a reasonable solution is container of smart pointers.

Why does storing references (not pointers) in containers in C++ not work?

Containers store objects. References are not objects.

The C++11 specification clearly states (§23.2.1[container.requirements.general]/1):

Containers are objects that store other objects.

Should I store entire objects, or pointers to objects in containers?

Since people are chiming in on the efficency of using pointers.

If you're considering using a std::vector and if updates are few and you often iterate over your collection and it's a non polymorphic type storing object "copies" will be more efficent since you'll get better locality of reference.

Otoh, if updates are common storing pointers will save the copy/relocation costs.

STL: Stores references or values?

STL Containers copy-construct and store values that you pass in. If you want to store objects in a container without copying them, I would suggest storing a pointer to the object in the container:

class abc;
abc inst;
vector<abc *> vec;
vec.push_back(&inst);

This is the most logical way to implement the container classes to prevent accidentally storing references to variables on defunct stack frames. Consider:

class Widget {
public:
void AddToVector(int i) {
v.push_back(i);
}
private:
vector<int> v;
};

Storing a reference to i would be dangerous as you would be referencing the memory location of a local variable after returning from the method in which it was defined.



Related Topics



Leave a reply



Submit