How do we use an ifstream vector?

M

maria

std::vector <ifstream> in[10];
//
string open_input[10]={
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

How do we open the first 5 files above
by using the vector in?
When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;
}

It doesn't work.

Thanks!

maria
}
 
A

Alf P. Steinbach

* 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).

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;

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.

//
string open_input[10]={

I'll assume that's

std::string const open_input[10] = {
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

How do we open the first 5 files above
by using the vector in?

Are you sure you need to have them all open simultanously?

It would be much, much easier to do one file at a time.

However (disclaimer: off-the-cuff code):

void throwX( char const s[] ) { throw std::runtime_error( s ); }

typedef boost::shared_ptr< std::ifstream > IfStreamPtr;

void open5Files(
std::string const names[], std::vector<IfStreamPtr>& in
)
{
std::vector<IfStreamPtr> result;
for( int i = 0; i < 5; ++i )
{
IfStreamPtr stream( new std::ifstream( names ) );

if( stream->fail() ) { throwX( "blah blah failed" ); }
result.push_back( stream );
}
result.swap( in );
}

void foo()
{
using namespace std;
static string const inFileNames[] = { "a", "b", ... };

vector<IfStreamPtr> inFiles;
open5Files( inFileNames, inFiles );
// Do things
}

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. I think
not, and then for abstracting up one would need a custom destruction
function for the boost::shared_ptr.

In short, the so-called /abstraction cost/ seems to be high for this
problem, but might be alleviated by using more suitable library classes.

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.open( inFileNames ) )
{
return false;
}
}

// Do things with the files, then:
return true;
}


When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;
}

It doesn't work.


"Doesn't work" is quite vague...

Cheers, & hth.,

- Alf


Disclaimer: none of code above ever touched by compiler's hands.
 
D

Daniel T.

maria said:
std::vector <ifstream> in[10];
//
string open_input[10]={
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

How do we open the first 5 files above
by using the vector in?
When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;
}

It doesn't work.


I wouldn't expect it to. :)

For one thing, streams are not copy-constructible or assignable, so they
can't be held in a vector. You can hold them in an array if you want
though, or you can hold pointers to them in a vector (preferably through
a smart pointer.)
 
M

maria

* 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).

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;

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.

//
string open_input[10]={

I'll assume that's

std::string const open_input[10] = {
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

How do we open the first 5 files above
by using the vector in?

Are you sure you need to have them all open simultanously?

It would be much, much easier to do one file at a time.

However (disclaimer: off-the-cuff code):

void throwX( char const s[] ) { throw std::runtime_error( s ); }

typedef boost::shared_ptr< std::ifstream > IfStreamPtr;

void open5Files(
std::string const names[], std::vector<IfStreamPtr>& in
)
{
std::vector<IfStreamPtr> result;
for( int i = 0; i < 5; ++i )
{
IfStreamPtr stream( new std::ifstream( names ) );

if( stream->fail() ) { throwX( "blah blah failed" ); }
result.push_back( stream );
}
result.swap( in );
}

void foo()
{
using namespace std;
static string const inFileNames[] = { "a", "b", ... };

vector<IfStreamPtr> inFiles;
open5Files( inFileNames, inFiles );
// Do things
}

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. I think
not, and then for abstracting up one would need a custom destruction
function for the boost::shared_ptr.

In short, the so-called /abstraction cost/ seems to be high for this
problem, but might be alleviated by using more suitable library classes.

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.open( inFileNames ) )
{
return false;
}
}

// Do things with the files, then:
return true;
}


When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;
}

It doesn't work.


"Doesn't work" is quite vague...

Cheers, & hth.,

- Alf


Disclaimer: none of code above ever touched by compiler's hands.


Thank you, Alf. I appreciate it.

maria
 
J

James Kanze

* 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.)
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.

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.)

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.
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.
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.
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.open( inFileNames ) )
{
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.
 
A

Alf P. Steinbach

* James Kanze:
* 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.

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.

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. :)

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.open( inFileNames ) )
{
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
 
J

James Kanze

* James Kanze:

[...]
State which other uses you think have been inappropriate.

Most. There seems to be a mode for using shared_ptr everywhere.
In practice, it's only appropriate in particular situations.
There is a safety net.
Where?

If you don't want that safety net, then use the C standard
library's functionality instead.

It's hard to define an array of a type which has a user defined
constructor in C.
It's even more convenient for this, not to mention, usually
more efficient.

Sorry, I don't understand. How is C more convenient for an
array of std::ifstream?
[...]
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.

More FUD. Just because you don't want to bother to learn
something new.
Write me that old copy-standard-input-to-output-exactly
program, portably for the platforms supporting that (Windows
and Unix suffices).

Formally, of course, it can't be done, either in C or in C++.
Practically, open both files in binary mode, and:
out << in.rdbuf() ;
does the trick in C++.

I fail to see the problem. Just because you've decided that you
want to be intentionally dense is no reason.
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.

IO streams, like the C FILE*, are designed around a particular
abstraction. For historical reasons (like FILE*), they support
other functionality, but less well. If you need a tool
implementing that abstraction, iostream is several orders of
magnitude better than FILE*. If you need a tool implementing
something else, then iostream may not be the answer. No tool
can be perfect for everything.
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.

Are you being intentionally dense, or just stupid. The above is
just name calling, with no justification in fact, as you well
know.
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.

The only one really relevant is the complexity at the user
level. It is slightly more complex to have to explicitely
allocate (using a new expression) each of the ifstream, rather
than let the compiler handle it automatically, e.g.:
std::ifstream inputs[ 10 ] ;
For the rest, I doubt that the differences are measurable.
This is another example of you being not right (wrt. previous
comments).

I wouldn't talk about being right if I were you. Given the
number of idiocies you spout off about iostream.
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.open( inFileNames ) )
{
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 what does your words "non-exception-based" version mean?
And nobody (except you) have claimed it is.
What got into you?

Just sick and tired of your incompentent idiocies. There are
things you know well, but iostream isn't one of them.
 
A

Alf P. Steinbach

* James Kanze:
* James Kanze:
[...]
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.

Most. There seems to be a mode for using shared_ptr everywhere.
In practice, it's only appropriate in particular situations.

Well. From the tone & formulations in the rest of the article I thought
the above was an attempt at implying, without saying so, that there had
been instances of me using shared_ptr really inappropriately, which you
had caught ("for once" agreed). Evidently that was not what you meant;
instead, it seems you meant that shared_ptr is overused in general.

But I don't think that's necessarily a bad thing.

For it is better with safe code that is perhaps a little less efficient
and a little more wordy than necessary, than unsafe use of raw pointers.
And also, teaching programmers to use a large ensemble of different
dedicated smart pointers correctly, is much more difficult than simply
promoting use of shared_ptr. As I recall, being a kind of simple potato
(can be used for just about anything and providing one common type for
shuffling data around) was a design goal of shared_ptr, and one reason
why extremely customizable policy based pointer was not adopted.

It's hard to define an array of a type which has a user defined
constructor in C.


Sorry, I don't understand. How is C more convenient for an
array of std::ifstream?

"C standard library" means you'd make that an array of FILE*.

A std::vector of smart pointers provides various safety nets. In
particular, using push_back (as the example code did) ensures that the
capacity is large enough for the number of items you put in. And it
provides the possibility of using checking at() instead of []. And it's
easier to pass safely as argument to functions. And so on. Of those
mentioned here, only using at() was not exemplified by the code.

That is not meant as an argument in favor of vector for this particular
problem, however, just clearing up what the safety net consists of,
since you're asking.

[...]
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.

More FUD. Just because you don't want to bother to learn
something new.

It would be re-memorizing some details of something old, not learning
something new.

Formally, of course, it can't be done, either in C or in C++.
QED.


Practically, open both files in binary mode, and:
out << in.rdbuf() ;
does the trick in C++.

I fail to see the problem. Just because you've decided that you
want to be intentionally dense is no reason.

Problem: "formally, of course, it can't be done".

IO streams, like the C FILE*, are designed around a particular
abstraction. For historical reasons (like FILE*), they support
other functionality, but less well. If you need a tool
implementing that abstraction, iostream is several orders of
magnitude better than FILE*. If you need a tool implementing
something else, then iostream may not be the answer. No tool
can be perfect for everything.

True, but misleading.

This particular tool fails to be applicable to simple problems such as
mentioned above.

Are you being intentionally dense, or just stupid. The above is
just name calling, with no justification in fact, as you well
know.

Mirror, James.

Also, language. :)

But in spite of that, I'll take you seriously, and provide details
refuting your stance:

* False sense of security: fact, yields illusion of type safe operation,
yet with Undefined Behavior, being defined in terms of fscanf.

* Maddeningly baroch and archaic: well, that's subjective, but just look
at code presented recently in this group. It seems to me that most C++
programmers (but not you, you seem to be expert in iostreams) strive
just to get the durned things to /do/ what's needed, except for the most
trivial. The complexity of the resulting code is staggering, and
provides a market for whole fat books detailing how to make them do
simple things.

* Requiring overly verbose client code: "overly" is subjective, but all
the << and >> stuff is bad enough, with manipulators thrown in. You're
one of very few that disagree with this assessment of verbosity.

* Often being grossly inefficient: it's been some years since last I
measured, but then FILE* outperformed iostreams easily, several times
faster (and API-level outperformed FILE*) with g++ and msvc. Also, the
new-fangled templated iostreams were far behind the old non-templated
ones in terms of efficiency. I'd put it as fact.

* Two-phase initialization externally and internally: fact.

* Hidden modes and failure state: fact.

* Undefined Behavior: just try inputting e.g. a hex number, fact.

* Safety as design goal: hm, I'd have a hard time proving that as a
fact, but do you really think it's not a fact, that safety /was not/ a
design goal? That the notion that safety was a design goal has "no
justification in fact", huh? :)

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.

The only one really relevant is the complexity at the user
level. It is slightly more complex to have to explicitely
allocate (using a new expression) each of the ifstream, rather
than let the compiler handle it automatically, e.g.:
std::ifstream inputs[ 10 ] ;
For the rest, I doubt that the differences are measurable.

It mounts up, with such complexity added in for just about anything you
want to do.

I wouldn't talk about being right if I were you. Given the
number of idiocies you spout off about iostream.

Language, James. I gather you're referring to the idiocies listed above
which you dismissed as "no justification in fact", such as iostreams
being designed for safety. Well.

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.open( inFileNames ) )
{
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 what does your words "non-exception-based" version mean?


"non-exception-based" means that this code is based on signaling
ordinary failure via a boolean return value instead of via an exception.

Instead of the earlier example's "throw", this one has "return".

It would be interesting if you could comment on whether this code /can/
throw exceptions other than for allocation failures. I ask because I
don't know and think you're an expert on technical details of iostreams.
But I allow for possibility that these beasts are complex enough that
even you don't know.

And nobody (except you) have claimed it is [exception safe].
What got into you?

Just sick and tired of your incompentent idiocies.

I'm not one keeping scores, but in this thread it's about 13 to 1 for me
on factual questions. I did goof in one sentence about shared_ptr, and
I'd have corrected that if you hadn't. Conversely, on name calling and
derogatory remarks, it's about 7 to 0 to you, or, as of this paragraph,
it's about 7 to 1 :). How about striving to reverse that trend?

There are things you know well, but iostream isn't one of them.

That is true.


Cheers,

- Alf
 
J

James Kanze

Alf said:
* James Kanze:

[...]
Well. From the tone & formulations in the rest of the article I thought
the above was an attempt at implying, without saying so, that there had
been instances of me using shared_ptr really inappropriately, which you
had caught ("for once" agreed). Evidently that was not what you meant;
instead, it seems you meant that shared_ptr is overused in general.

Not just you. Most of the time I see shared_ptr (or other smart
pointers) recommended here, it is inappropriate. shared_ptr is
fairly tricky to use correctly, and should be avoided by a
beginner.
But I don't think that's necessarily a bad thing.
For it is better with safe code that is perhaps a little less
efficient and a little more wordy than necessary, than unsafe
use of raw pointers.

I don't know where you get this idea that raw pointers are
unsafe. Anything is unsafe if used incorrectly. And for the
most typical use of pointers, navigation, raw pointers are both
safer and easier to use than shared_ptr. Try using shared_ptr
for navigation, and you'll quickly end up with all sorts of
problems: memory leaks, multiple deletes of the same object,
premature deletes, etc.
And also, teaching programmers to use a large ensemble of
different dedicated smart pointers correctly, is much more
difficult than simply promoting use of shared_ptr.

As a programmer evolves, he will learn to use specific smart
pointers in the specific cases where they are appropriate.
As I recall, being a kind of simple potato (can be used for
just about anything and providing one common type for
shuffling data around) was a design goal of shared_ptr, and
one reason why extremely customizable policy based pointer was
not adopted.

If that's the case, shared_ptr doesn't meet that design goal. I
rather doubt that that was the goal, however, since shared_ptr
never existed without its partners: scoped_ptr and weak_ptr.
The fact that it needs such partners is a good indication of the
complexity it introduces, and why beginners should avoid it, or
at least why using it should never be automatci.

[...]

So what's your point? That a tool designed for portably reading
and writing text can't be used with binary transparency? That's
a fact of life.
Problem: "formally, of course, it can't be done".

Yes, because formally, the problem is unsolvable on some
systems. Remember CP/M?
True, but misleading.
This particular tool fails to be applicable to simple problems
such as mentioned above.

If you don't know it, and refuse to learn it. I use it
systematically for such problems, and I've never seen a better
tool for them. I could probably design one, but in doing so,
I'd start with iostream, and correct its one or two minor short
comings (naming convention, error reporting, and I'd probably
drop support for everything that wasn't a text stream).

[I've deleted most of the ranting which followed, because it
is simply false.]
 
A

Alf P. Steinbach

* James Kanze:
Alf said:
* James Kanze:
On Feb 2, 1:39 pm, "Alf P. Steinbach" <[email protected]> wrote:
[...]
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.
Most. There seems to be a mode for using shared_ptr everywhere.
In practice, it's only appropriate in particular situations.
Well. From the tone & formulations in the rest of the article I thought
the above was an attempt at implying, without saying so, that there had
been instances of me using shared_ptr really inappropriately, which you
had caught ("for once" agreed). Evidently that was not what you meant;
instead, it seems you meant that shared_ptr is overused in general.

Not just you.

Then, if I still took you seriously, I would have to again ask you to
come with at least one example, which you avoided -- but see below.

Most of the time I see shared_ptr (or other smart
pointers) recommended here, it is inappropriate. shared_ptr is
fairly tricky to use correctly, and should be avoided by a
beginner.

"shared_ptr ... should be avoided by a beginner"

I don't know where you get this idea that raw pointers are
unsafe.

"I don't know where you get this idea that raw pointers are unsafe."


[snip]
[I've deleted most of the ranting which followed, because it
is simply false.]

Your statements, name calling etc. sound like goading, but then, with so
much of it and so forcefully expressed I'm now not sure that you don't
really think you mean what you write.

There is a fine line between, on the one hand, good-natured bantering,
exaggeration and the technique of hyperbole, and, on the other hand,
being ungood, and I'm sorry to tell you that you have crossed that line
and some other lines repeatedly and by miles in this thread.


Concerned,

- Alf
 
J

James Kanze

* James Kanze:

[...]
Your statements, name calling etc. sound like goading, but then, with so
much of it and so forcefully expressed I'm now not sure that you don't
really think you mean what you write.
There is a fine line between, on the one hand, good-natured bantering,
exaggeration and the technique of hyperbole, and, on the other hand,
being ungood, and I'm sorry to tell you that you have crossed that line
and some other lines repeatedly and by miles in this thread.

Yes. I realised that I'd gotten a bit out of hand shortly after
sending that last posting. I apologize. I don't know why, but
there's something about the way you express yourself which gets
to me. It's personal---I know other people who have no problem
with you, but do have problems with people who don't get on my
nerves. And I can't find any concrete reason why I react this
way. I know that you are more than competent---you've proved it
often enough in the past, and that there's usually something
behind your opinion, even when we disagree.

What's upsetting me is your attacks on iostream. I know that
you don't like them. Fine, but... your complaints seem to be a
haphazard mixture at several different levels, which makes it
difficult to respond reasonably. And you don't suggest an
alternative: several of your complaints (including some of the
most justified) are a direct result of the semantics being based
on stdio, so presumably, you don't like that either. My problem
is first and foremost, what do you teach beginners in C++---I
haven't found anything better than iostream to date. And from
an engineering point of view, I don't find the minor flaws of
iostream important enough to justify writing an alternative.

I don't argue that iostream is perfect. Even Jerry Schwartz'
initial design had some minor flaws (e.g. the naming
conventions, and error reporting in general), and in this case,
the ISO committee certainly didn't help things. On the other
hand, I do think that it is fundamentally a very original and
very effective design---I would recommend the original design,
for example, as an example of exactly how a good design chooses
between virtual functions (in streambuf) and function
overloading (the << and >> operators) to allow different types
of extendibility.

So on one hand, I'm interested in hearing what you'd propose
which meet the design criteria: extendability to user defined
sinks and sources, extendability to user defined types, and a
possibility for users to define their own "format specifiers"
(manipulators, in iostream---I don't know what in other designs,
because iostream is the only design I've seen which supports
it). stdio obviously fails on all three counts, in addition to
being fundamentally unsafe. The only other alternatives I'm
aware of are boost::format and GB_Format/Gabi::Format. Both of
which are strongly based on iostream.

With regards to some specific complaints you mentioned (from
memory, I don't have your original posting handy):

Two phase initialization:
I'm not really sure what you're complaining about here. A
priori, the reason two phase initialization isn't a good
thing in general is that it requires client code to be able
to deal with an invalid object. But that reason doesn't
apply to IO---user code must always be able to deal with an
invalid object (regardless of the design), because it is the
nature of IO that once valid objects become invalid during
use. After fopen, if I receive a non-null FILE*, I know
that I have a valid open file, but as soon as I've executed
the first operation on it, I'm back in the same situation as
I am with iostream. It does make things more difficult for
the client code, but it is a fact of life with IO; you can't
get around it.

Undefined behavior when inputting numeric values:
This is, of course, inherited from stdio, and also affects
boost::format. (But not GB_Format! I reimplemented all of
the numeric conversion functions myself. It's not something
I'd recommend---definitly too much work for too little
benefit.) From a quality of implementation point of view, I
expect that all implementations in fact handle overflow
correctly---the ones I regularly use do. If yours doesn't,
then you should complain loudly to the vendor.

Which is, of course, no excuse for such laxity in the
standard. I've just written up a proposal to fix it, which
I will submit as soon as I get a document number to do so.
(The deadline for the next mailing is 9AM Monday morning,
PST. Given the time differences between here and there,
there's even a good chance that I get it in that mailing.)

The fact that there is persistent state:
I'm not sure that you expressed it like that, but if I
remember correctly, you didn't like the idea of the
formatting options being handled by class state. From a
purely design point of view, I agree, but I've not seen an
alternative which avoids this problem, and meets the other
design requirements. Until proven otherwise, I'll consider
it a necessary evil.

Performance:
That is, of course, very implementation dependent. The
modifications made by the standard committee didn't help
anything here. Still, it's possible to implement iostream
so that it is even faster than stdio---Dietmar Kuehl had a
proof of concept implementation at one time, I believe.

In the meantime, I've never had to renounce using iostream
because of performance concerns. I suspect that this is
fairly general, and that it accounts why even the best best
current implementations (Dinkumware, g++, etc.) haven't made
the effort of improving performance, e.g. by using Dietmar's
ideas.

And I'll grant you the criticisms concerning error detection and
recovery---it's definitly iostream's weak point. That, and the
fact that the function names sometimes take some getting used
to, to put it mildly. (IMHO, the most serious flaw in the
design is that eofbit does double duty---internally, to remember
that an EOF has been seen from the streambuf, and externally, to
tell the user why the last request failed. These really should
be separated.)

Anyway, my challenge remains: what do you recommend to
beginners, and why? How is it better?

(And I am sorry about the previous posting. Every time we
manage to discuss something reasonably, it turns out to be very
enriching. Hopefully, starting this discussion over...)
 
A

Alf P. Steinbach

* James Kanze:
* James Kanze:
[...]
Your statements, name calling etc. sound like goading, but then, with so
much of it and so forcefully expressed I'm now not sure that you don't
really think you mean what you write.
There is a fine line between, on the one hand, good-natured bantering,
exaggeration and the technique of hyperbole, and, on the other hand,
being ungood, and I'm sorry to tell you that you have crossed that line
and some other lines repeatedly and by miles in this thread.

Yes. I realised that I'd gotten a bit out of hand shortly after
sending that last posting. I apologize. I don't know why, but
there's something about the way you express yourself which gets
to me. It's personal---I know other people who have no problem
with you, but do have problems with people who don't get on my
nerves. And I can't find any concrete reason why I react this
way. I know that you are more than competent---you've proved it
often enough in the past, and that there's usually something
behind your opinion, even when we disagree.

Well, perhaps consider James Dennett's advice (which he learned from
someone else):


Before fighting with a man, first walk a mile in his shoes. Then
not only will you be a mile away from him, you'll also have his
shoes.


But please then also consider that I can ill afford losing a pair of shoes.

[snip technical stuff, I'll have to think about, but as mentioned in
some thread long ago what I see as key is far more separation of
concerns, a more layered and at top level specialized approach]


Cheers,

- Alf
 
M

msebor

std::vector <ifstream> in[10];
//
string open_input[10]={
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"

};

How do we open the first 5 files above
by using the vector in?
When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;

}


Try:

#include <fstream>

std::ifstream in [10];

const char* const open_input[] = {
"TEMPLATE_1", "TEMPLATE_2", "TEMPLATE_3", "TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6", "TEMPLATE_7", "TEMPLATE_8", "TEMPLATE_9",
"TEMPLATE_10"
};

int main ()
{
for (int i = 0; i < 5; ++i) {
if (!in .rdbuf ()->open (open_input , std::ios::in))
return 1;
}
}
 
H

Howard Hinnant

maria said:
std::vector <ifstream> in[10];
//
string open_input[10]={
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

How do we open the first 5 files above
by using the vector in?
When I try

for (i=0; i<5; i++) {
if (!in(open_input.c_str(), ios::in)) {
return 1;
}

It doesn't work.

Thanks!

maria
}


Just fyi, the current C++0X working paper will support code very close
to that above. More like:

std::vector<std::ifstream> in(10);
string open_input[10]={
"TEMPLATE_1",
"TEMPLATE_2",
"TEMPLATE_3",
"TEMPLATE_4",
"TEMPLATE_5",
"TEMPLATE_6",
"TEMPLATE_7",
"TEMPLATE_8",
"TEMPLATE_9",
"TEMPLATE_10"
};

for (i=0; i<5; i++) {
if (!in.open(open_input.c_str(), ios::in)) {
return 1;
}

Freescale's CodeWarrior 10, no longer available on a desktop platform,
is the only currently existing implementation I'm aware of.

-Howard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,183
Messages
2,570,967
Members
47,516
Latest member
ChrisHibbs

Latest Threads

Top