views:

173

answers:

3

Why does the following not work:

#include <iostream>
#include <fstream>
#include <stack>

std::stack<std::ifstream> s;

-PT

+10  A: 

std::stack (like all STL containers) requires that its contained type be "assignable". In STL-speak, that means that it must have a copy constructor and an operator=. std::ifstream has neither of these.

You can imagine why you would not want to be able to copy and assign I/O streams; the semantics of what should happen when there are two copies of the same stream are not obvious. Should a read from or write to one copy affect the position of the other copy? Should closing one stream close the other? etc.

If you want to have "a container of std::ifstreams", then what you really should make is "a container of std::ifstream*s". Non-const pointers are always assignable. The caveat is that in this case of course you have to make sure that you delete the pointers yourself before destructing the container, since the container will not do that for you.

Tyler McHenry
However, you can have a stack of ifstream pointer : std::stacked<std:ifstream *> s;
Frank
Outstanding! Thank you. - Prasoon
A: 

Backing up Tyler here (after voting +1).

The stl containers make copies all over the place of the objects you give them. If you want, you can deal with this by giving them special objects with carefully crafted copy constructors and destructurs with reference counting and whatnot.

Generally, I find that way too much trouble. Just as a rule of thumb, only use small objects in the containers. If you want to make a stack of structures or classes, use pointers to them instead.

T.E.D.
As my rule of thumb: 1) only compose (higher-level) classes of members that implement copying properly (e.g `std::string`, not `char*`), 2) else store smart pointers (and make sure the class is non-copyable).
UncleBens
Even if you do #1, in my (typically real-time) work, copying large objects around, or anything that may involve a dynamic allocation/deallocation, is a Bad Thing.
T.E.D.
In such case you probably use special memory pools etc (since you can't allocate the pointers dynamically) which makes for rather specific usage of C++. Would you really consider it good advice for a beginner to avoid `vector<string>` in favour of `<vector<string*>`? IMO, the overhead doesn't normally matter, except in very specific scenarios.
UncleBens
+1  A: 

Because streams are non copyable you can tecxhnicaly put them into standard containers.

But we can get around that by storeing pointers to the stream. But you dont want to store pointers to streams (especially if they are dynamically allocated) in a standard container. So we look to boost for a solution.

Boost has the concept of pointer containers.
This allows you to dynamically allocate an object and store the pointer in the pointer container which then takes ownership of the object and gives you access to the dynamic object as if it were the object (rather than a pointer).

Because the pointer container takes ownership you don;t need to worry about deleting the object. The container will do that.

Because it gives access to the contained objects as objects rather than pointers it allows you to use the stream in standard algorithms in a more natural fashon (campared with a container of pointers).

Martin York