Thread: Simple file close & clear question

  1. #1
    Registered User
    Join Date
    May 2016
    Posts
    40

    Simple file close & clear question

    I have a two simple questions on the code below.
    (1) I take it that when closing an ofstream file object, you don't have to supply a filename ?

    (2) The execution leaves the function creating the ofstream at the sub function call. I'm thinking in this case the ofstream object would stay in existence. But can it be used again when the sub-function returns as is ? Or does it need closed, cleared and re-opened ?
    Code:
    int ReVestCls::DrawDownCalc()
    { 
     ofstream ofstr_DrawDnFile("DrawDown.txt");  
    
     if (!ofstr_DrawDnFile.good())
     { cerr << "Problem opening DrawDown file" << endl; exit(1); }
       // . . .
       // other code  
    
       ofstr_DrawDnFile.close(); 
       ofstr_DrawDnFile.clear();
    
       Re_InVestCalc();
    
       ofstr_DrawDnFile.open("DrawDown.txt", ios_base::out | ios_base::app );
       // . . .
       // other code 
      
       return 0;
    }

  2. #2
    Guest
    Guest
    (1) The (o)fstream can only manage one file at a time, so there's no ambiguity what you are closing.

    (2) Not sure I understand your question, but the call on line 13 will not (directly) affect the local objects surrounding it – they can be used as if nothing happened in between.

  3. #3
    Registered User
    Join Date
    May 2016
    Posts
    40
    Quote Originally Posted by Guest View Post
    (1) The (o)fstream can only manage one file at a time, so there's no ambiguity what you are closing.

    (2) Not sure I understand your question, but the call on line 13 will not (directly) affect the local objects surrounding it – they can be used as if nothing happened in between.
    No I understand it only manages one file at a time. Specifically upon returning to the fuction from the sub-function call, does that ofstream need closed, cleared and re-opened ?

    Or is all that not necessary and just assume it's still open?

  4. #4
    Guest
    Guest
    It's still open, nothing has changed. The object is local and the function isn't able to touch it unless you explicitly pass its memory location (which you don't).

    Look at the following code:
    Code:
    void fn() { // doing some stuff }
    
    int main()
    {
        int obj = 5;
        fn();
        cout << obj << endl;
    }
    You wouldn't expect obj to change state after fn() has been called, right? What makes you doubt this behavior when the object in question is a std::ofstream instead?

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    What's important is if the Re_InvestCalc() actually touches the same file. You can use two different file objects to manipulate the same file, it just gets slightly confusing. If you want to mix reads and writes, a read following a write needs to be preceded by a ostream::flush(). (IOW, the writing file handle needs to flush its output or close before you read from the same file.) Also, take care not to overwrite your file at all. As long as you do that, you should be able to do what you want and let RAII take over closing files for you in the file objects' destructor.
    Last edited by whiteflags; 07-11-2016 at 09:57 PM.

  6. #6
    Registered User
    Join Date
    May 2016
    Posts
    40
    Quote Originally Posted by Guest View Post
    It's still open, nothing has changed. The object is local and the function isn't able to touch it unless you explicitly pass its memory location (which you don't).

    Look at the following code:
    Code:
    void fn() { // doing some stuff }
    
    int main()
    {
        int obj = 5;
        fn();
        cout << obj << endl;
    }
    You wouldn't expect obj to change state after fn() has been called, right? What makes you doubt this behavior when the object in question is a std:fstream instead?
    Uh well that makes perfect sense now that you put it like that. As a novice learner I was apprehensive since I read that ofstream object (ptr or container or whatever it actually is) automatically closes as it goes out of scope.

    If speaking totally in terms of stack memory being released walking back up each call, then obviously a sub-function down further on stack memory would not put a calling function out of current (rather it's own) stack frame scope.

    But honestly I did not know "where" the compiler creates the function nor am I yet totally under each aspect of "scope" be it class, stack or otherwise. And therein my own testing of the matter might depict inconclusive results. So I wanted the voice of experience to comment. And I thank you much for that Adrian.

    Quote Originally Posted by whiteflags View Post
    What's important is if the Re_InvestCalc() actually touches the same file. You can use two different file objects to manipulate the same file, it just gets slightly confusing. If you want to mix reads and writes, a read following a write needs to be preceded by a ostream::flush(). (IOW, the writing file handle needs to flush its output or close before you read from the same file.) Also, take care not to overwrite your file at all. As long as you do that, you should be able to do what you want and let RAII take over closing files for you in the file objects' destructor.
    Thanks whiteflags, I am more aware of those aspects than I currently am all the "scope" aspects. But I thank you for all and any clarification at this point in my journey.
    Last edited by R_W_B; 07-12-2016 at 06:51 AM. Reason: clarity

  7. #7
    Guest
    Guest
    The calling function maintains the state prior to entering the stack frame of the sub-function and – after returning from that – is reinstated to continue the computation. I cannot imagine how hard programming would be, if every function call killed all other objects

    One thing that might help you get a better sense of scope is using a class that notifies you of its own creation and destruction. Instantiating such an object at different places in your code gives you feedback on its lifetime (and that of others in its place).
    Code:
    struct X
    {
        X(const string& n = "X") : name(n) { cout << name << " lives!" << endl; }
        ~X() { cout << name << " dies." << endl; }
        string name;
    };
    
    int main()
    {
        X x1("foo");
        cout << "---------" << endl;
        { // you can create plain blocks such as this to test scope behavior
            X x2("bar");
            cout << "---------" << endl;
        }
        cout << "---------" << endl;
    }
    Output:
    Code:
    foo lives!
    ---------
    bar lives!
    ---------
    bar dies.
    ---------
    foo dies.
    Last edited by Guest; 07-12-2016 at 07:40 AM.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, technically speaking, all state lives on the stack, regardless of how many functions are called. Just think of it as a stack of boxes. Every time a function gets called, it puts a new box on the top of the stack. When the function ends, it removes the box (i.e. clean up everything it put on the stack). All other boxes on the stack are not affected.

    Classes are no exception to this. It lives when it is first created and dies when the function (or the local scope) it is declared in ends.

    There would be "exceptions" to these rules when you start talking about statics, globals and the heap. But otherwise these rules are absolute.
    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
    Registered User
    Join Date
    May 2016
    Posts
    40
    Thanks to both replies, could you please help me on this new confusion? I don't readily understand why I got the error. ( labeled with comment just after -> sName.clear(); )
    Code:
    int ReVestCls::Re_InVestCalc()
    { 
     stringstream ssName;
     ssName << "ReInvest_" << iPeriod_Ct << ".txt";
     string sName(ssName.str());
     const char* ccpFilename = sName.c_str();
     ofstream ofstr_ReVest(ccpFilename); // Open new ReVest file
    
     if (!ofstr_ReVest.good())
     { cerr << "Problem opening ReVest file" << endl; exit(1); }
      
     // Initial output data  ** Prints only once at top of file **  //fDrawDownPmt is a Class var
     ofstr_ReVest << fixed << setprecision(2) << "Initial purchase Deposit " << fDrawDownPmt << endl;
      
     int i = 1;
     while( i < iPeriod_Ct)
     {
      ofstr_ReVest.close();
      ofstr_ReVest.clear();
      ssName.str("");
      ssName.str( std::string() ); // overkill here from desperation
      ssName.clear();
      ssName << "ReInvest_" << i << ".txt";
      sName.clear();
    
    //  sName(ssName.str());  //<-[Error] no match for call to '(std::string {aka std::basic_string<char>}) (std::basic_stringstream<char>::__string_type)'
    //  ccpFilename = sName.c_str();
    
      string sName2(ssName.str());  // different string fixes ?
    
      ccpFilename = sName2.c_str();
    
      ofstr_ReVest.open(ccpFilename, ios_base::out | ios_base::app ); // append mode, Open pertinent ReVest file
      // No code created here yet, just the simple test write below.
      ofstr_ReVest << "value for i is " << i << " Value for iPeriod_Ct is " << iPeriod_Ct << endl;
      i++;
     }
      
      cout << " Leaving Re_InVestCalc Func" << endl;
      return 0;
    }

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >>sName(ssName.str());
    Should be
    sName = ssName.str();

    You can't "call" a string; it makes no sense. You really wanted to assign the generated string from the stringstream to the string, but that's really not necessary either, which brings me to the next point:

    >> string sName(ssName.str());
    >> const char* ccpFilename = sName.c_str();
    >> ofstream ofstr_ReVest(ccpFilename); // Open new ReVest file
    This can be simplified to just:
    ofstream ofstr_ReVest(ssName.str()); // Open new ReVest file
    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.

  11. #11
    Registered User
    Join Date
    May 2016
    Posts
    40
    Quote Originally Posted by Elysia View Post
    >>sName(ssName.str());
    Should be
    sName = ssName.str();

    You can't "call" a string; it makes no sense. You really wanted to assign the generated string from the stringstream to the string, but that's really not necessary either, which brings me to the next point:

    >> string sName(ssName.str());
    >> const char* ccpFilename = sName.c_str();
    >> ofstream ofstr_ReVest(ccpFilename); // Open new ReVest file
    This can be simplified to just:
    ofstream ofstr_ReVest(ssName.str()); // Open new ReVest file
    Oh ok, so my top declaration
    string sName(ssName.str());
    only worked the since it was a declaration with initialization. That makes sense, thanks.

    However on your last suggestion of,
    ofstream ofstr_ReVest(ssName.str()); brings an error [Error] no matching function for call to 'std::basic_ofstream<char>::basic_ofstream(std::ba sic_stringstream<char>::__string_type)'

    so I surmise you meant,
    ofstream ofstr_ReVest(ssName.str().c_str());

    I did know about this but have read in some cases getting garbage or undefined results when tacking the return of c_str() into a combo function call. Something about the temp memory of the c_str return.
    This particular example I'm sure is safe if you say so, but with my experience I just chose not to combine the two and keep the calls separate.

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I'm assuming you're using gcc.
    By default, gcc doesn't compile with respect to the newest standard (it still compiles with respect to the 98/03 standard, which in my opinion, is a mistake since it's been 5 years since C++11 came out).
    Try including in your command line or your IDE -std=c++17/1z/14/1y/11/0x. That means you should try -std=c++17 first, then if that doesn't work, -std=c++1z, and so on. The compiler switches change depending on the version you have. Optimally, you should have the latest version, though.

    Due to an oversight, the C++98/03 standard did not have overloads for streams that took an std::string. That was fixed in C++11, so what I originally wrote is correct, adhering to the C++11 standard.
    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.

  13. #13
    Registered User
    Join Date
    May 2016
    Posts
    40
    Quote Originally Posted by Elysia View Post
    I'm assuming you're using gcc.
    By default, gcc doesn't compile with respect to the newest standard (it still compiles with respect to the 98/03 standard, which in my opinion, is a mistake since it's been 5 years since C++11 came out).
    Try including in your command line or your IDE -std=c++17/1z/14/1y/11/0x. That means you should try -std=c++17 first, then if that doesn't work, -std=c++1z, and so on. The compiler switches change depending on the version you have. Optimally, you should have the latest version, though.

    Due to an oversight, the C++98/03 standard did not have overloads for streams that took an std::string. That was fixed in C++11, so what I originally wrote is correct, adhering to the C++11 standard.
    Yes TDM-GCC with code gen set currently to GNU C++11. It has another option I have not tried which is ISO C++11. But these are all I have at this point, which is my own fault since I have been busy with other stuff and have not downloaded the free Visual Community yet.

    I thank you (as always) for offering the most efficient way, however I was writing the extra lines of code rather than (at my point in the game) trying to decipher when it's ok to use the str().c_str() combo calls.

    Understandably my specific example here could have flown ok (as you say) but I wasn't sure of it.
    There are several web articles on the various combo cravats but this is one of the shorter explanations.
    Sense Codons: Don't let std::stringstream.str().c_str() happen to you

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's OK to do it the longer way if you're uncertain. The basic principle to understand here is that std::stringstream.str() returns a temporary string. Then you call c_str() on that temporary object, giving you a const char* pointer. But when that temporary string goes out of scope, that pointer becomes invalid. What you can generally consider is that temporaries live at least for the duration of the line it was created on. So the example in your link you see someCStyleFunction( myStringStream.str().c_str() ), and this is correct since the temporary string created by str() outlives the function call.

    Now, there is a caveat. The pointer will only live for the function call, or in your code, the constructor call. If the constructor stores away the pointer for later use, it's going to become a problem. However, fstream only needs the pointer to open the file. After that, it doesn't need the pointer any more*, so we're all good.

    *) This is not guaranteed by the standard as far as I know, but I know no sane implementation that would store the pointer because pretty much any OS will give you back a file handle to use to identify the file you've opened.
    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.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    *) This is not guaranteed by the standard as far as I know, but I know no sane implementation that would store the pointer because pretty much any OS will give you back a file handle to use to identify the file you've opened.
    OS considerations aside, a more general implementation issue is that the stream has no guarantees about the lifetime of what the pointer points to either, so if it wants to keep the string, it has to make a copy.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple question about file I/O.
    By The7thCrest in forum C++ Programming
    Replies: 2
    Last Post: 02-04-2009, 05:15 PM
  2. simple file I/O question
    By loopshot in forum C Programming
    Replies: 2
    Last Post: 11-30-2006, 02:59 PM
  3. simple File I/O question
    By bobnet in forum C++ Programming
    Replies: 4
    Last Post: 10-25-2003, 06:53 AM
  4. FYI - a simple way to clear the screen
    By johnc in forum C Programming
    Replies: 13
    Last Post: 07-17-2002, 04:53 PM
  5. Replies: 8
    Last Post: 11-21-2001, 12:13 AM

Tags for this Thread