vector of fstream, does not work?

S

Someonekicked

In my program, I need to open multiple files, and I wont know till after the
program execution how many of them (user will enter that value). So I am
using a vector of fstream. I am using fstream since I will need to write and
read from files, and I am using those files as binary files.

I made a sample of what's going on (below). Without using vector, everything
works fine, but with using vectors, something is going wrong somewhere!??

I compiled the code with MS VC6++, and it compiled without errors, but still
the piece of code with vectors wont give correct answer.
with MSV .net 2003, compiling the code with vector will give me error,
something about (no copy constructor available or copy constructor is
declared 'explicit'), is that the problem?

*********** First , without vector ********
fstream inoutData;
inoutData.open("trial.txt", ios::binary | ios::in | ios::eek:ut);
if(!inoutData)
{
ofstream newfile;
newfile.open("trial.txt",ios::binary);
newfile.clear();
newfile.close();
inoutData.clear();
inoutData.open("trial.txt", ios::binary | ios::in | ios::eek:ut);
}

int p = 24;
inoutData.clear();
inoutData.seekp(0);
inoutData.write(reinterpret_cast<const char *>(&p), sizeof(p));
inoutData.seekg(0);
int q;
inoutData.read(reinterpret_cast< char *>(&q), sizeof(q));
cout << q << endl;


*********** Second , with vector ********

vector<fstream> inoutData(1);
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
if(!inoutData[0])
{
ofstream newfile;
newfile.open("trial.txt",ios::binary);
newfile.clear();
newfile.close();
inoutData[0].clear();
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
}

int p = 24;
inoutData[0].clear();
inoutData[0].seekp(0);
inoutData[0].write(reinterpret_cast<const char *>(&p), sizeof(p));
inoutData[0].seekg(0);
int q;
inoutData[0].read(reinterpret_cast< char *>(&q), sizeof(q));
cout << q << endl;
 
J

Jerry Coffin

In my program, I need to open multiple files, and I wont know till after the
program execution how many of them (user will enter that value). So I am
using a vector of fstream. I am using fstream since I will need to write and
read from files, and I am using those files as binary files.

A vector of fstream isn't allowed. Anything you put into
a vector must be assignable, and an fstream isn't -- the
assignment operator is private in std::ios_base, and
(unless I've missed something) none of its descendents
makes it public again.

You'll probably need to do something like an array of
(possibly smart) pointers to fstreams instead.
 
T

Tsubasa

Jerry coffin, I find your error in your answer that is not
std::ios_base but std::basic_ios, you know? 'cause the assignment
operator is public in std::ios_base, and is private&not defined in
std::basic_ios, although std::ios_base is the base of std::basic_ios,
and std::basic_istream comes from std::basic_ios, std::fstream comes
from std::basic_istream,
I suppose that you might write error, don't you?
 
T

Tsubasa

and, OK, I ignore another mistake: anything you put into a vector must
be assignable. It's not necessary, but copy constructor must be PUBLIC.
 
K

Kai-Uwe Bux

Tsubasa said:
Jerry coffin, I find your error in your answer that is not
std::ios_base but std::basic_ios, you know? 'cause the assignment
operator is public in std::ios_base, and is private&not defined in
std::basic_ios, although std::ios_base is the base of std::basic_ios,
and std::basic_istream comes from std::basic_ios, std::fstream comes
from std::basic_istream,
I suppose that you might write error, don't you?

From the standard:

27.4.2 Class ios_base

namespace std {
class ios_base {
public:
class failure;
typedef T1 fmtflags;
static const fmtflags boolalpha;
...
[lots of stuff snipped]
...
static bool sync_with_stdio(bool sync = true);
protected:
ios_base();
private:
// static int index; exposition only
// long* iarray; exposition only
// void** parray; exposition only
private:
ios_base(const ios_base&);
ios_base& operator=(const ios_base&);
};

Note the private copy constructor and assignment operator, each of which by
itself makes ios_base and classes derived therefrom unsuitable for use in
std::vector.


Best

Kai-Uwe Bux
 
A

Axter

Someonekicked said:
In my program, I need to open multiple files, and I wont know till after the
program execution how many of them (user will enter that value). So I am
using a vector of fstream. I am using fstream since I will need to write and
read from files, and I am using those files as binary files.

I made a sample of what's going on (below). Without using vector, everything
works fine, but with using vectors, something is going wrong somewhere!??

I compiled the code with MS VC6++, and it compiled without errors, but still
the piece of code with vectors wont give correct answer.
with MSV .net 2003, compiling the code with vector will give me error,
something about (no copy constructor available or copy constructor is
declared 'explicit'), is that the problem?

*********** First , without vector ********
fstream inoutData;
inoutData.open("trial.txt", ios::binary | ios::in | ios::eek:ut);
if(!inoutData)
{
ofstream newfile;
newfile.open("trial.txt",ios::binary);
newfile.clear();
newfile.close();
inoutData.clear();
inoutData.open("trial.txt", ios::binary | ios::in | ios::eek:ut);
}

int p = 24;
inoutData.clear();
inoutData.seekp(0);
inoutData.write(reinterpret_cast<const char *>(&p), sizeof(p));
inoutData.seekg(0);
int q;
inoutData.read(reinterpret_cast< char *>(&q), sizeof(q));
cout << q << endl;


*********** Second , with vector ********

vector<fstream> inoutData(1);
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
if(!inoutData[0])
{
ofstream newfile;
newfile.open("trial.txt",ios::binary);
newfile.clear();
newfile.close();
inoutData[0].clear();
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
}

int p = 24;
inoutData[0].clear();
inoutData[0].seekp(0);
inoutData[0].write(reinterpret_cast<const char *>(&p), sizeof(p));
inoutData[0].seekg(0);
int q;
inoutData[0].read(reinterpret_cast< char *>(&q), sizeof(q));
cout << q << endl;

IAW C++ standard, iostream and derived class fstream are not assignable
or copiable, which means you can't use it as a concrete object in your
vector.
However, you could create a vector of pointer to fstream.
I would recommend using a smart pointer like boost::shared_ptr
See following link of list of smart pointers:
http://axter.com/smartptr/other_smart_pointers.htm

And see following link for example usage of smart pointers:
http://axter.com/smartptr/index.htm
 
J

Jerry Coffin

@i40g2000cwc.googlegroups.com>, (e-mail address removed)
says...
Jerry coffin, I find your error in your answer that is not
std::ios_base but std::basic_ios, you know? 'cause the assignment
operator is public in std::ios_base, and is private&not defined in
std::basic_ios, although std::ios_base is the base of std::basic_ios,
and std::basic_istream comes from std::basic_ios, std::fstream comes
from std::basic_istream,
I suppose that you might write error, don't you?

I was pretty sure ios_base declared them private, but
maybe my memory has failed me.

It's more or less beside the point which base class
causes it though. Creating a vector of X requires that X
be copyable and assignable. Streams are neither copyable
nor assignable, so you can't create vectors of streams.
 
H

Howard Hinnant

"Someonekicked said:
In my program, I need to open multiple files, and I wont know till after the
program execution how many of them (user will enter that value). So I am
using a vector of fstream. I am using fstream since I will need to write and
read from files, and I am using those files as binary files.

In addition to the good answers you've already received, I'd like to
add: The committee is seriously considering changes to the C++ language
and standard library which allow your "with vector" example to work
exactly as you coded it.

Reference:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html

-Howard
 
T

Tom

In my opinion, the element type used for vector should be a value-like
type. And the fstream, manages a file handler, cannot be copy and
assign.
 
H

Howard Hinnant

"Tom said:
In my opinion, the element type used for vector should be a value-like
type. And the fstream, manages a file handler, cannot be copy and
assign.

No worries.

vector::value_type will continue to be value-like. And fstream will
continue to be non-copyable and non-assignable. Move semantics
introduces a powerful new way of looking at things that compliments your
existing views, and allows things to be more efficient, not less.

Consider:

std::fstream
open_the_file_my_way(const char* filename)
{
std::fstream result ...
return result;
}

....

void test ()
{
std::fstream my_file = open_the_file_my_way("the file");
...
}

There is no logic error above. Every time the fstream changes
locations, the old location is about to be destroyed. The underlying
file handle can be passed from fstream to fstream, and no one is the
wiser. You get what today seems like copy behavior, but really is move
behavior.

At the same time, you will still be prohibited from copying or assigning
fstreams:

void test ()
{
std::fstream my_file = open_the_file_my_way("the file"); // ok
...
std::fstream another_file = my_file; // won't compile
}

Here if the copy succeeded you would have two streams running around
pointing to the same file. I think we're all agreed that would be a bad
thing. This will continue to be enforced at compile time.
*********** Second , with vector ********

vector<fstream> inoutData(1);
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
if(!inoutData[0])
{
ofstream newfile;
newfile.open("trial.txt",ios::binary);
newfile.clear();
newfile.close();
inoutData[0].clear();
inoutData[0].open("trial.txt", ios::binary | ios::in | ios::eek:ut);
}

int p = 24;
inoutData[0].clear();
inoutData[0].seekp(0);
inoutData[0].write(reinterpret_cast<const char *>(&p), sizeof(p));
inoutData[0].seekg(0);
int q;
inoutData[0].read(reinterpret_cast< char *>(&q), sizeof(q));
cout << q << endl;

In the OP's code, the fstream is never copied, even while it is inside
the vector. If the OP attempts an operation with the vector<fstream>
that would *visibly* copy an fstream, the compiler will reject it. E.g.

vector<fstream> inoutData(1); // ok
fstream f = inoutData[0]; // compile time error
inoutData.push_back(fstream("another file")); // ok

In the latest example, no one has a reference to that temporary being
put into the vector. There's no danger of two fstreams pointing to the
same file.

fstream f;
inoutData.push_back(f); // compile time error

If this compiled, then both f and inoutData.back() would point to the
same file (bad!).

-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

Similar Threads


Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top