views:

141

answers:

3
+1  Q: 

Redirecting in C++

#include <iostream>
#include <fstream>
using namespace std;

void foo(){
  streambuf *psbuf;
  ofstream filestr;
  filestr.open ("test.txt");
  psbuf = filestr.rdbuf(); 
  cout.rdbuf(psbuf);    
}

int main () {
  foo();
  cout << "This is written to the file";
  return 0;
}

Does cout write to the given file?

If not, is there a way to do it without sending the variables to foo, like new?

A: 

It seems to me that your code should work but ... Why don't you try yourself ? You will see if everything is written in test.txt or not.

Ugo
It seems to me that it doesn't, but your question is still valid :-)
Johnsyweb
@johnsyweb Oh right filestr is destroyed. I didn't read carefully ...
Ugo
+4  A: 

I suspect that by now compiled and run your code and found that you get a segmentation fault.

You are getting this because you create and open an ofstream object within foo(), which is then destroyed (and closed) at the end of foo. When you attempt to write to the stream in main(), you attempt to access a buffer which no longer exists.

One workaround to this is to make your filestr object global. There are plenty of better ones!

Edit: Here is a better solution as suggested by @MSalters:

#include <iostream>
#include <fstream>

class scoped_cout_redirector
{
public:
    scoped_cout_redirector(const std::string& filename)
        :backup_(std::cout.rdbuf())
        ,filestr_(filename.c_str())
        ,sbuf_(filestr_.rdbuf())
    {
        std::cout.rdbuf(sbuf_);
    }

    ~scoped_cout_redirector()
    {
        std::cout.rdbuf(backup_);
    }

private:
    scoped_cout_redirector();
    scoped_cout_redirector(const scoped_cout_redirector& copy);
    scoped_cout_redirector& operator =(const scoped_cout_redirector& assign);

    std::streambuf* backup_;
    std::ofstream filestr_;
    std::streambuf* sbuf_;
};


int main()
{
    {
        scoped_cout_redirector file1("file1.txt");
        std::cout << "This is written to the first file." << std::endl;
    }


    std::cout << "This is written to stdout." << std::endl;

    {
        scoped_cout_redirector file2("file2.txt");
        std::cout << "This is written to the second file." << std::endl;
    }

    return 0;
}
Johnsyweb
"There are better ones". Indeed, but it would be hard to find them without a pointer. Here's one: read up on RAII. Most of the code from the function `foo` should really be moved to a constructor, and the matching destructor should do the cleanup (such as restoring cout to its old state).
MSalters
Indeed. @mati seems to have deliberately omitted restoring `cout` to its former state when lifting the code out of http://www.cplusplus.com/reference/iostream/ios/rdbuf/ into `foo()`. RAII seemed too far out of the scope of the question.
Johnsyweb
A: 

thenk you but all specially Johnsyweb. but i cant use a soltion that uses class or uses global so plz can some
give me soltion that use new. also pasing the from main to foo

streambuf *psbuf;
ofstream filestr;

should work right?

i am tring to do this but its not working y?
i pass the streem to foo so it exist in the main so it wont end whan foo finsh.

 void foo(streambuf *psbuf){

  ofstream filestr;
  filestr.open ("test.txt");
  psbuf = filestr.rdbuf(); 
  cout.rdbuf(psbuf);    
}

int main () {
streambuf *psbuf
  foo(psbuf);
  cout << "This is written to the file";
  return 0;
}
mati
1. Updates to your question should be presented as edits to the question, not answers. 2. Not using globals I can understand. What on Earth is restricting you from using *classes* in C++ ?. 3. `new` isn't going to help you here. Really. Really, really. 4. What are you looking to pass into `foo()`? 5. The two lines of code are in your initial question. I explained why they didn't work in my answer.
Johnsyweb
You cannot use a solution that use classes? So streambuf and ofstream are not classes?
Sam
@mati, following your edit, you **still** create and open an ofstream object within foo(), which is then destroyed (and closed) at the end of foo. Same problem.
Johnsyweb
Moreover, `cout` is a *global* instance of a *class*, so both globals and classes are going to be used regardless!
Johnsyweb