Re: How do we use an ifstream vector?
* James Kanze:
On Feb 2, 12:30 am, "Alf P. Steinbach" <al...@start.no> wrote:
* maria:
std::vector <ifstream> in[10];
Uhm, first, an ifstream is not copy-constructible (for what
would it mean to copy a stream?), so you can't place it
directly in a vector.
Your compiler should not have accepted that; try to check
whether there is some option to be more standard-conforming
(e.g. for g++ -std c++98, IIRC).
It's undefined behavior, so the compiler is not required to
complain. For g++, -std=c++98 tells the compiler to use the
1998 language standard, but does not impact the library. For
that, he wants -D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG
-D_GLIBCXX_DEBUG_PEDANTIC. (I think it is the first which is
important here, but I just go ahead and use all three. Be
warned, however, that these options may change the size of
certain structures, so code compiled with them is not compatible
with code compiled without them.)
Second, if hypothetically ifstream could serve as vector element type,
the above would declare a raw array of ten empty vectors.
You might instead do
typedef boost::shared_ptr< std::ifstream > IfStreamPtr;
std::vector<IfStreamPtr> in;
For once:-). Agreed. This is one place where shared_ptr is
just the ticket. (Of course, the next version of the standard
will support move semantics, and will allow a vector of
ifstream. But I wouldn't count on it any time soon.)
State which other uses you think have been inappropriate.
Or, from a practical point of view, to avoid having to deal with all
that, but also then coding without a safety net, just use a raw array of
ifstream, default-initialized, and then open() each one.
I'm not sure where the problem with that is, if the array is a
local object. With g++, at least, unless you're compiling with
the options I mention above, you don't have any safety net with
vector, either, and with Sun CC (with either the Rogue Wave
version of the library or the STL port), there aren't even any
options to provide the safety net.
There is a safety net.
If you don't want that safety net, then use the C standard library's
functionality instead.
It's even more convenient for this, not to mention, usually more efficient.
I'd still use an std::vector of boost::shared_ptr, of course,
but in this case, that's only because it is the expected idiom,
and anything else will cause the reader to wonder. (In
practice, I only use C style arrays when I need to achieve
static initialization, or when the profiler says I must.)
[...]
This code does some ungood things such as using a magic number
(namely 5) and using ifstream pointers rather than abstracting
up to istream. I couldn't recall whether istream has virtual
destructor or not.
Are you kidding? All classes in the standard which have virtual
functions have a virtual destructor. (In this case, the base
class ios_base has a virtual destructor.)
Nope, I'm not kidding, and I'm not assuming anything iostream is reasonable.
You really should stop spreading FUD about iostream. If you
don't like them, don't use them, but they happen to be the best
alternative by far that we have, and used correctly, the
actually work very well.
Write me that old copy-standard-input-to-output-exactly program,
portably for the platforms supporting that (Windows and Unix suffices).
This demonstrates that instead of -- as you maintain -- working
well, there are trivial and very reasonable and very practically useful
problems for which they don't work at all.
It's perhaps worse for the problems where they sort of work, e.g. giving
a false sense of security, being maddeningly baroch and archaic,
requiring overly verbose client code, often being grossly inefficient,
etc. ad nauseam, including having two-phase initialization both
externally and internally, having hidden modes and failure state, and
exhibiting Undefined Behavior at the slightest provocation, when safety
was the problem they were meant to address.
I think not, and then for abstracting up one would need a
custom destruction function for the boost::shared_ptr.
Sorry, but boost::shared_ptr doesn't require that the destructor
by virtual---it will always call the destructor on the type of
pointer passed into it.
Yes.
You don't need to be sorry. :-)
For once (e.g. see above or below), you're right. <g>
In short, the so-called /abstraction cost/ seems to be high
for this problem, but might be alleviated by using more
suitable library classes.
More FUD. The only abstraction cost is the extra allocations of
std::vector. Probably not even measurable, compared to the time
used to read a file.
Simply compare (1) the code size, (2) the complexity of the code, and,
although it doesn't matter in practice here, (3) the (in-) efficiency
(which contrary to what you state also include dynamic allocations of
ifstreams and dynamic allocations inherent in using boost::shared_ptr).
Abstraction cost is not only ineffiency.
This is another example of you being not right (wrt. previous comments).
The raw array and non-exception-based version:
#define ARRAY_SIZE( a ) (sizeof(a)/sizeof(*a))
bool foo()
{
using namespace std;
static char const* const inFileNames[] = { "a", "b", ... };
ifstream inFiles[ARRAY_SIZE(inFileNames)];
assert( ARRAY_SIZE(inFileNames) >= 5 );
for( int i = 0; i < 5; ++i )
{
if( !inFiles[i].open( inFileNames[i] ) )
{
return false;
}
}
// Do things with the files, then:
return true;
}
Still more FUD. The above is perfectly exception safe. The
only problem it has is that it isn't the usual idiom, so the
reader will ask why.
Yes, it's correct that your comment here is more FUD. :-) Nobody's said
it wasn't exception safe. And nobody (except you) have claimed it is.
What got into you?
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?