|
-
February 19th, 2005, 10:05 PM
#1
vector of fstream type
Im no expert of C++ but I have a preety general understanding. Sometimes I try and make effecent code and others I just want to experiment and reevent the wheel. Right now Im trying to take, by take I mean hide all the ugly fstream code, by creating an object, FileStream, that holds various functions ie, textOpenRead that would open a text file for reading. I thought the best way to do this would be to create two vectors, one that olds an int(ID), and another that holds the fstream object.
The ID would serve the purpose of when calling, lets say getLine(int ID). Then the object would match the ID with the correct fstream object and apply getLine to that file. I hope I was able to make myself clear enough, but just for safety's sake Im gonna show an example and source.
Code:
//Header
#include <fstream>
#include <vector>
using namespace std;
class FileStream
{
private:
vector<int> ID;
vector<fstream>streams;
public:
FileStream(){}
~FileStream(){}
int textOpenRead(char*);
void getLine(int id);
};
//This is suppose to return the id that is used for later functions for editing
int FileStream::textOpenRead(char *fName)
{
fstream file(fName,ios::out);//Create the fstream object
streams.push_back(file); //Here is where I get errors
ID.push_back(ID.size());
return ID.size()-1;
}
void getLine(int id)
{
char ch;
while(streams[i].get(ch)!=null or enter or endOfFile)
{
cout<<ch;
}
}
//End Header
The getline code I just wrote and is obviously just there for the sake of understanding. For some reason I ger errors at the "streams.push_back(file);" line.
The errors are as follows according to Log:
In copy constructor
`std::basic_ios<char, std::char_traits<char> >::basic_ios(const
std::basic_ios<char, std::char_traits<char> >&)':
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_construct.h:78: instantiated from `void std::_Construct(_T1*, const _T2&) [with _T1 = std::fstream, _T2 = std::basic_fstream<char, std::char_traits<char> >]'
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_vector.h:599: instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::fstream, _Alloc = std::allocator<std::fstream>]'
FileStream.h:21: instantiated from here
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/ios_base.h:668: error: `
std::ios_base::ios_base(const std::ios_base&)' is private
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_construct.h:78: error: within
this context
C:/Program Files/Dev-Cpp/include/c++/3.3.1/streambuf: In copy constructor `
std::basic_filebuf<char, std::char_traits<char> >::basic_filebuf(const
std::basic_filebuf<char, std::char_traits<char> >&)':
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_construct.h:78: instantiated from `void std::_Construct(_T1*, const _T2&) [with _T1 = std::fstream, _T2 = std::basic_fstream<char, std::char_traits<char> >]'
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_vector.h:599: instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::fstream, _Alloc = std::allocator<std::fstream>]'
FileStream.h:21: instantiated from here
C:/Program Files/Dev-Cpp/include/c++/3.3.1/streambuf:922: error: `
std::basic_streambuf<_CharT, _Traits>::basic_streambuf(const
std::basic_streambuf<_CharT, _Traits>&) [with _CharT = char, _Traits =
std::char_traits<char>]' is private
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_construct.h:78: error: within
this context
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/ios_base.h: In member function
`std::basic_ios<char, std::char_traits<char> >& std::basic_ios<char,
std::char_traits<char> >::operator=(const std::basic_ios<char,
std::char_traits<char> >&)':
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/vector.tcc:230: instantiated from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<_Tp*, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::fstream, _Alloc = std::allocator<std::fstream>]'
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/stl_vector.h:603: instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::fstream, _Alloc = std::allocator<std::fstream>]'
FileStream.h:21: instantiated from here
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/ios_base.h:671: error: `
std::ios_base& std::ios_base::operator=(const std::ios_base&)' is private
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/vector.tcc:230: error: within
this context
C:/Program Files/Dev-Cpp/include/c++/3.3.1/streambuf: In member function `
std::basic_filebuf<char, std::char_traits<char> >& std::basic_filebuf<char,
std::char_traits<char> >::operator=(const std::basic_filebuf<char,
std::char_traits<char> >&)':
C:/Program Files/Dev-Cpp/include/c++/3.3.1/streambuf:925: error: `
std::basic_streambuf<_CharT, _Traits>& std::basic_streambuf<_CharT,
_Traits>::operator=(const std::basic_streambuf<_CharT, _Traits>&) [with
_CharT = char, _Traits = std::char_traits<char>]' is private
C:/Program Files/Dev-Cpp/include/c++/3.3.1/bits/vector.tcc:230: error: within
this context
make.exe: *** [main.o] Error 1
Execution terminated
Any help you can give me on how to properly get a fstream vector. Maybe I shouldn't be using fstream as the ojbect or maybe it just can't be done.
Any light you can shine on the subject is greatly appreciated.
Thank you.
[gorregisguy]
-
February 19th, 2005, 10:27 PM
#2
Re: vector of fstream type
I don't think that you can copy fstream objects. I guess you need to
hold pointers instead ... vector<fstream*>.
-
February 19th, 2005, 10:43 PM
#3
Re: vector of fstream type
I was under the impression that a vector was a better array, and since arrays can hold any data type, vectors can too. But like I said I'm fairly new to this. The problem with the pointers though, as far as I know, is that what the vector is pointing at will no longer exist at the end of the function.
Thank you for the repley.
[gorregisguy]
-
February 20th, 2005, 02:26 AM
#4
Re: vector of fstream type
 Originally Posted by gorregisguy
I was under the impression that a vector was a better array, and since arrays can hold any data type, vectors can too.
A vector has strict requirements of what can be placed in it.
For vector<T>, type T must be copyable, assignable, and default constructable. An fstream is not copyable or assignable, therefore it cannot be placed in a vector. The reason why this is a requirement is that unlike arrays, vectors are dynamically resizable. To accomplish this, the vector must be able to copy and move elements from one location to another. If your object cannot be copied, then it doesn't satisfy the requirements for a vector.
Basically, this simple test is all you need to see if your type can be stored in a vector:
Code:
int main()
{
T a;
// assume a has some "live data"
T b = a;
T c;
c = a;
}
where "T" is the type you want to store in the vector. These are the types of operations that vector will be performing on T.
It the above code doesn't compile, then T cannot be used in a vector. If the code does compile, but doesn't run correctly (from start to finish), then T can not be safely used in a vector (but vector will accept it, regardless of the runtime bugs that will occur).
Note that if T is an int, double, float, i.e. a simple type, the following code works. Replace T with fstream, and you see that the program above won't even compile. If you replace T with a buggy user-defined class (usually a class that needs a user-defined copy constructor, assignment operator, and destructor, but one of those three are missing), the code will compile, but running the program causes problems.
Regards,
Paul McKenzie
-
February 20th, 2005, 08:07 AM
#5
fstream, make your own
Thank you Paul McKenzie. Do you or anyone else know if I could possibly make my own fstream class from scratch. I know I can make other standard classes from scratch, ie the string class and cmath. And if possibly how would you go about doing that.
Any information is greatly appricated.
[gorregisguy]
-
February 20th, 2005, 09:53 AM
#6
Re: fstream, make your own
 Originally Posted by gorregisguy
Thank you Paul McKenzie. Do you or anyone else know if I could possibly make my own fstream class from scratch. I know I can make other standard classes from scratch, ie the string class and cmath. And if possibly how would you go about doing that.
Well...rather than questioning whether this is possible or not, I would rather question the approach in the first place...in other words, in my eyes this is the wrong conclusion you have generated from the posts.
I would rather say, you should reconsider your design....why do you need a vector of streams in the first place? Furthermore....you can still use pointers to these streams instead as being mentioned.
-
February 20th, 2005, 11:34 AM
#7
Re: vector of fstream type
Thank you for the response Andreas Masur. I had wanted to a vector of streams so that I could simplfy the creating,writing, and opeing of files. By having one object that keeps track of all fstreams open. May seem pointless to some but it's something I need. In regards to why don't I just have a pointer of fstreams, like I said before, I don't belive that is possible because the fstream is created at the beggining of the function and no longer exists at the end.
Thank you for you time.
[gorregisguy]
-
February 20th, 2005, 01:04 PM
#8
Re: vector of fstream type
 Originally Posted by gorregisguy
In regards to why don't I just have a pointer of fstreams, like I said before, I don't belive that is possible because the fstream is created at the beggining of the function and no longer exists at the end.
This doesn't stop you from placing the address of the fstream that is created in the vector<fstream*>. I don't see how a vector of fstream could have helped you as opposed to a vector of fstream*.
The only difference is that the vector<fstream> will call the destructor of the fstream objects when the vector goes out of scope, and invariably when the vector needs to be resized. This is another reason why vector<fstream> is highly dangerous. A vector is going to call the destructor of your objects, due mostly to vector resizing. The fstream destructor closes the stream, causing more problems if the vector goes ahead and destructs your fstream without you knowing about it.
It seems if you have little choice but to use a vector of fstream pointers, or create a class that manages the fstream's by making that class responsible for creating and destroying the fstreams (similar to a factory class). You still need to use pointers, however.
Regards,
Paul McKenzie
-
February 20th, 2005, 01:10 PM
#9
Re: vector of fstream type
See boost::shared_ptr (www.boost.org).
Code:
std::vector< boost::shared_ptr< std::fstream > > g_my_streams;
Hope this helps
-
February 20th, 2005, 01:14 PM
#10
Re: fstream, make your own
 Originally Posted by gorregisguy
Thank you Paul McKenzie. Do you or anyone else know if I could possibly make my own fstream class from scratch.
I agree with Andreas. This is the wrong approach and you should rethink your design.
I know I can make other standard classes from scratch, ie the string class
Only an experienced C++ programmer can do this correctly. Many "novice" C++ programmers (usually programmers who know other languages well but not C++) have tried this and failed miserably.
Regards,
Paul McKenzie
-
February 20th, 2005, 01:41 PM
#11
Re: vector of fstream type
The string class isn't as hard as some may belive it to be. I modeled the one I made off the Java String class. Making my own fstream class seems impossible, to me at least. Im not sure if it is my complier or just the way the STD is set up but finding the orginal source for fstream is extremily hard, so there is nothing I can look at to get a good general idea.
As far as rethinking my orginal design, I haven't a clue on how to have an(one) object that controls all the file input and output with simplicity. I'll go back to the drawing board and see if there is anything I may have missed.
Thank you again for your replies,
[gorregisguy]
-
February 20th, 2005, 02:05 PM
#12
Re: vector of fstream type
 Originally Posted by gorregisguy
The string class isn't as hard as some may belive it to be. I modeled the one I made off the Java String class.
And without seeing it, I doubt that it is nearly as efficient as the one provided by the standard STL 'string' class...again...this is a typical error many developer from other languages make...before re-inventing the wheel, simply explore the facilities the other languag already provides.
As for the rest....what compiler are you using?
-
February 20th, 2005, 03:17 PM
#13
Re: vector of fstream type
DevC++ by BloodShed. It's the best free complier I've found. And do you happen to know of a way to test the String class' efficiency, for my own benefit.
[gorregisguy]
-
February 20th, 2005, 04:49 PM
#14
Re: vector of fstream type
 Originally Posted by gorregisguy
The string class isn't as hard as some may belive it to be. I modeled the one I made off the Java String class.
It is hard, believe me, and I've been using C++ for over 15 years now. A lot goes into making the string class that matches the standard std::string class. Look at the Gnu C++ implementation of std::string (Gnu is used by Dev-cpp). Look at what it takes to get everything done right (it is a reference counted string class).
As I stated before, many novice or new C++ programmers have attempted this, and failed. Bugs, inefficiencies, etc. all caused the home-made string class to be thrown out, and to use just the std::string class. Only an experienced C++ programmer would know exactly what it takes to make any class that rivals what the standard classes gives you.
Making my own fstream class seems impossible, to me at least.
I have never seen a programmer have to create their own fstream handling class from scratch.
Im not sure if it is my complier or just the way the STD is set up
It has nothing to do with the compiler, but it has everything to do with what the ANSI standard states how fstream is supposed to behave. Copying an fstream object is undefined behavior. Be lucky your compiler caught the error, because you would have been having all sorts of problems if your compiler's fstream implementation exposed (inappropriately) the copy constructor or assignment operator for fstream. You would have then asked why your program is behaving strangely instead of why you are getting the compiler errors.
but finding the orginal source for fstream is extremily hard
It is not hard at all, it's all there in <fstream>.
As far as rethinking my orginal design, I haven't a clue on how to have an(one) object that controls all the file input and output with simplicity.
Wrap the fstream in a class, and keep a reference count so that if copies are created, you just bump up the reference count, and decrement the reference count when objects are destroyed. Or have a map of filenames to fstream instances, or something like that.
The bottom line is that there is no simple class that is the solution. You should scrub the idea of keeping fstream instances in a vector (unless they are fstream pointers) or creating fstream from scratch. All it takes is to use the existing fstream and creating your own classes that manages fstreams.
For example:
Code:
#include <map>
#include <fstream>
#include <string>
typedef std::map<const std::string, std::fstream *> StreamMap;
class FileWrapper
{
//...
private:
std::string TheName;
std::fstream *TheStream;
static StreamMap s_AllStreams;
public:
FileWrapper( ) : pStream(NULL) { }
fstream *OpenStream( const std::string& filename )
{
if ( s_AllStreams.find( filename ) != s_AllStreams.end() )
{
return s_AllStreams[filename];
}
TheStream = new fstream( filename );
s_AllStreams[filename] = pStream;
TheName = filename;
return TheStream;
}
void CloseStream( )
{
StreamMap::iterator it = s_AllStreams.find( TheName );
if ( it != s_AllStreams.end() )
{
if ( TheStream == it->second )
{
delete TheStream;
TheStream = NULL;
s_AllStreams.remove( it );
}
}
}
void CloseAllStreams( )
{
// write code to iterate through the static map and delete streams
StreamMap::iterator it = s_AllStreams.begin();
StreamMap::iterator it2 = s_AllStreams.end();
while ( it != it2 )
{
delete it->second;
++it;
}
s_AllStreams.clear();
}
};
A very rough idea with a lot of missing code (it also was not compiled), but this is what you should be trying to do. The interface to open and close a stream is OpenStream and CloseStream. A static map of the name and stream created is used. Whenever a new stream is opened or closed, an update of the map is done. If you need to close all the streams, iterate through the static map and delete each stream.
Again, this may not be the ideal design, but it is a design nevertheless that doesn't rely on undefined behavior or vectors of fstream instances (which can't compile anyway, and would be disastrous at runtime if it could compile).
I'll go back to the drawing board and see if there is anything I may have missed.
That's the problem -- it isn't that you've missed anything, it is the design that you've chosen can't be used.
Regards,
Paul McKenzie
-
February 20th, 2005, 05:08 PM
#15
Re: vector of fstream type
Paul, thank you. You have helped me understand what I must do now. I do still have a question. I noaticed in a few places you wrote std:: instead of just writting using namespace std; a the top. Is that a habit or maybe it causes the complier or the program longer to complie/load.
Also you seem to have missunderstood a few of my quotes. When I said "Im not sure if it is my complier or just the way the STD is set up" I wasn't inferring to the errors I was getting but the fact that I could not find the source code of fstream. And in fact it is hard, in the fstream header on my computer all it states is what other headers to include. And each one of those only show the function and its arguments. The acutall source code is in other files with strange names, and it becomes hard to choose the right one.
As far as the string class being hard to make. I don't doubt you, I'm sure mine isn't as effeicent as the standard one but it was only a, see if I can do it, kind of thing.
Thank you again for all the help,
[gorregisguy]
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|