Thread: yes, file streams are not file pointers

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    222

    yes, file streams are not file pointers

    Hi,

    well today for 1000-th time i learned that file streams are not file pointers and that a vector of fstreams is not allowed.

    ok, so i guess i get that now, non the less i still need a solution to a following problem:

    I need to write to multiple files and the number of files are not known in advance that is I know them only when i process some data. Moreover the writing is not dome consecutively (first write in file 1 then in file 2 ....) but as i am processing something i get a number that tels me to which file it should be written.

    so what would be an alternative (C++ alternative) to :

    Code:
    std::vector<std::fstream> outFiles_fs(x);
    std::vector<std::vector<std::fstream>> outFile2dArray_fs(y,outFiles_fs);
    I could convert streams to file pointers and then proceed but is there a better way ?

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    This seems to work:
    Code:
    #include <iostream>
    #include <vector>
    #include <fstream>
    
    
    int main()
    {
        std::vector<std::ofstream*> v;
    
    
        v.push_back(new std::ofstream("data1.txt"));
        v.push_back(new std::ofstream("data2.txt"));
    
    
        int n = 42;
        *v[0] << n;
        *v[1] << n;
    
    
        delete v[0];
        delete v[1];
    
    
        return 0;
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    In C++11 it's better to do:
    Code:
    #include <vector>
    #include <fstream>
    #include  <memory> 
     
    int main()
    {
        std::vector<std::unique_ptr<std::ofstream>> v{};
     
        v.emplace_back(new std::ofstream("data1.txt"));
        v.emplace_back(new std::ofstream("data2.txt"));
     
        int n = 42;
        *v[0] << n;
        *v[1] << n;
     
        return 0;
    }
    In C++14 you could use make_unique, which is even better.
    Last edited by King Mir; 09-14-2013 at 11:32 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    733
    First of all, vector<ofstream> wasn't right until C++11. Since C++11, vector<ofstream> and vector<vector<ofstream>> are both valid.

    In C++03 there were no move semantics and STL containers required their values to be CopyConstructible and CopyAssignable. Currently, std::vector primarily requires its values to be only MoveConstructible and MoveAssignable, and std::ofstream certainly is. The only problem is that its move construction may throw exception, and thus certain vector modifications do not guarantee strong exception safety (unlike vector of unique_ptrs).

    If you plan to store your container somewhere and/or you want more abstraction, consider using std::vector<std::unique_ptr<std::ostream>> (it will work not only on files, but also with other streams, e.g., console).

    Code:
    std::vector<std::ofstream> v1; // valid in C++11
    
    std::vector<std::unique_ptr<std::ofstream>> v2;
    
    std::vector<std::unique_ptr<std::ostream>> v3;
    If you don't know what to choose, answer the following:
    1. Are vectors only temporaries which work only on files? Use v1.
    2. Are vectors only temporaries which work on different types of streams? Use v3.
    3. Are vectors stored somewhere (e.g., in an object) and work only on files? Use v1 or v2 (v2 - stronger exception safety).
    4. Are vectors stored somewhere (e.g., in an object) and work on different types of streams? Use v3.

    Note: v3 can be used in all of the above situations, because it provides higher abstraction and guarantees stronger exception safety.
    Last edited by kmdv; 09-15-2013 at 02:54 AM.

  5. #5
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    Thank you for the help, but now i have another question. I don't know when each file will pop-up therefore i need to create a d2 vector that captures all possible combinations that will eventually come up and as they appear open a file and write to it. Therefore, pushing or emplacing is not an option unless there is a way to push it to a specific position. so is it possible to do something like this :

    Code:
    
    int main()
    {
        std::vector<std::unique_ptr<std::ofstream>> v1{};
        std::vector<std::vector<std::unique_ptr<std::ofstream>>> v(1,v1);
        v[0][0] = new std::ofstream("data1.txt")); // segmentation fault here
      
        int n = 42;
        *v[0][0] << n;
      
     
        return 0;
    }
    Last edited by baxy; 09-15-2013 at 03:45 AM.

  6. #6
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    UPDATE TO MY PREVIOUS POST:

    I don't get it , so if i use it like this it works :

    Code:
    int main(){
        std::vector<std::fstream*> v1(1);
        std::vector<std::vector<std::fstream*>> v(1,v1);
        v[0][0] = new std::fstream; 
       (*v[0][0]).open("data.txt",std::ios::out);
        int n = 42;
        *v[0][0] << n;
       (*v[0][0]).close();
    }
    but i cannot even compile it when using unique_ptr. why is that?

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Are you using a C++11 compiler? Have you #include'd all the necessary headers?
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The problem is two-fold:

    First, streams are only moveable, but vector does not have a constructor that move constructs a sequence. It can only copy construct a sequence. What does this mean? It means that it does something like this:

    AllocSpace();
    m_elem[0] = arg[0];
    // ...

    This makes copies of the arguments you pass to it which is not allowed. Therefore, this cannot work.

    Second, unique_ptr's constructor is explicit, therefore, this does not work:

    std::unique_ptr<int> p;
    p = new int;

    You must explicitly create a new unique_ptr and move it into the new one:

    std::unique_ptr<int> p;
    p = std::unique_ptr<int>(new int);

    Another problem that can bite you in the ass is that you use arrays unsafely. Use .at() instead of the index operator. It will prevent undefined behaviour, allowing you to find bugs at an earlier stage. You can read more here: http://sourceforge.net/apps/mediawik..._arrays_in_Cpp
    Putting all this together, you get (which I tested):

    Code:
    int main()
    {
    	typedef std::unique_ptr<std::ofstream> Val_t;
    	typedef std::vector<Val_t> InnerVector_t;
    
    	std::vector<InnerVector_t> v;
    	v.emplace_back();
    	v.at(0).emplace_back(new std::ofstream("data1.txt"));
    
    	int n = 42;
    	*v.at(0).at(0) << n;
    
    
    	return 0;
    }
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    @baxy,
    In your code in post #6 you've left out the all important delete but included a completely unnecessary close.

    When you delete the fstream object its destructor will be called which will close the file.

    The possibility of forgetting to delete the object is why people are telling you to use unique_ptr, whose constructor will call delete.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  10. #10
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    Thank you all. This was extremely helpful. Thank you !!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File Streams or File Descriptors?
    By charlitos in forum C Programming
    Replies: 1
    Last Post: 04-08-2009, 09:07 PM
  2. Replies: 3
    Last Post: 12-22-2002, 02:48 PM
  3. File streams
    By zog&cog in forum C++ Programming
    Replies: 8
    Last Post: 04-07-2002, 09:25 AM
  4. Help with file Streams
    By venomgts550 in forum C++ Programming
    Replies: 2
    Last Post: 12-10-2001, 04:35 PM
  5. file streams
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 11-15-2001, 04:52 PM