c++fileiofstream

How do I assign a fstream to an fstream* in C++?


I'm writing a function in C++ that has to return more than one value, and I know that I can't. So I thought to pass the function two pointers to the files I want to open. This is the code and then I'll explain my problem:

void openSourceOutputFiles(string sourceFilename, string outputFilename,
                           fstream *source, fstream *output){
    fstream sourceFile(sourceFilename);
    fstream outputFile(outputFilename);

    *source = sourceFile;
    *output = outputFile;
}

I'm compiling with G++, and it says that I can't assign to the fstream* pointer an fstream. I tried also to modify it as this:

void openSourceOutputFiles(string sourceFilename, string outputFilename,
                           fstream *source, fstream *output){
    fstream sourceFile(sourceFilename);
    fstream outputFile(outputFilename);

    *source = &sourceFile;
    *output = &outputFile;
}

but it didn't work. This is instead the full code I'm working on:

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

string sourceFilename, outputFilename;
string sourceContent, outputContent;
fstream *source, *output;

void getSourceOutputFiles(string *source, string *output) {
    cout << "Source ";
    cin >> *source;
    cout << "Output ";
    cin >> *output;
}

void openSourceOutputFiles(string sourceFilename, string outputFilename,
                           fstream *source, fstream *output){
    fstream sourceFile(sourceFilename);
    fstream outputFile(outputFilename);

    *source = &sourceFile;
    *output = &outputFile;
}

int main() {
    getSourceOutputFiles(&sourceFilename, &outputFilename);
    openSourceOutputFiles(sourceFilename, outputFilename, *source, *output);
    return 0;
}

G++ error:

main.cpp: In function 'void openSourceOutputFiles(std::string, std::string, std::fstream*, std::
fstream*)':
main.cpp:22:15: error: no match for 'operator=' (operand types are 'std::fstream' {aka 'std::bas
ic_fstream<char>'} and 'std::fstream*' {aka 'std::basic_fstream<char>*'})
   22 |     *source = source;
      |               ^~~~~~
In file included from main.cpp:3:
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:7: note: can
didate: 'std::basic_fstream<_CharT, _Traits>& std::basic_fstream<_CharT, _Traits>::operator=(std
::basic_fstream<_CharT, _Traits>&&) [with _CharT = char; _Traits = std::char_traits<char>]'
 1186 |       operator=(basic_fstream&& __rhs)
      |       ^~~~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:33: note: 
no known conversion for argument 1 from 'std::fstream*' {aka 'std::basic_fstream<char>*'} to 'st
d::basic_fstream<char>&&'
 1186 |       operator=(basic_fstream&& __rhs)
      |                 ~~~~~~~~~~~~~~~~^~~~~
main.cpp:23:15: error: no match for 'operator=' (operand types are 'std::fstream' {aka 'std::bas
ic_fstream<char>'} and 'std::fstream*' {aka 'std::basic_fstream<char>*'})
   23 |     *output = output;
      |               ^~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:7: note: can
didate: 'std::basic_fstream<_CharT, _Traits>& std::basic_fstream<_CharT, _Traits>::operator=(std
::basic_fstream<_CharT, _Traits>&&) [with _CharT = char; _Traits = std::char_traits<char>]'
 1186 |       operator=(basic_fstream&& __rhs)
      |       ^~~~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:33: note: 
no known conversion for argument 1 from 'std::fstream*' {aka 'std::basic_fstream<char>*'} to 'st
d::basic_fstream<char>&&'
 1186 |       operator=(basic_fstream&& __rhs)
      |                 ~~~~~~~~~~~~~~~~^~~~~
PS C:\Users\Allenips Development\Documents\C-C++\Varm> g++ main.cpp -o main.exe
main.cpp: In function 'void openSourceOutputFiles(std::string, std::string, std::fstream*, std::
fstream*)':
main.cpp:22:15: error: no match for 'operator=' (operand types are 'std::fstream' {aka 'std::bas
ic_fstream<char>'} and 'std::fstream*' {aka 'std::basic_fstream<char>*'})
   22 |     *source = source;
      |               ^~~~~~
In file included from main.cpp:3:
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:7: note: can
didate: 'std::basic_fstream<_CharT, _Traits>& std::basic_fstream<_CharT, _Traits>::operator=(std
::basic_fstream<_CharT, _Traits>&&) [with _CharT = char; _Traits = std::char_traits<char>]'
 1186 |       operator=(basic_fstream&& __rhs)
      |       ^~~~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:33: note: 
no known conversion for argument 1 from 'std::fstream*' {aka 'std::basic_fstream<char>*'} to 'st
d::basic_fstream<char>&&'
 1186 |       operator=(basic_fstream&& __rhs)
      |                 ~~~~~~~~~~~~~~~~^~~~~
main.cpp:23:15: error: no match for 'operator=' (operand types are 'std::fstream' {aka 'std::bas
ic_fstream<char>'} and 'std::fstream*' {aka 'std::basic_fstream<char>*'})
   23 |     *output = output;
      |               ^~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:7: note: can
didate: 'std::basic_fstream<_CharT, _Traits>& std::basic_fstream<_CharT, _Traits>::operator=(std
::basic_fstream<_CharT, _Traits>&&) [with _CharT = char; _Traits = std::char_traits<char>]'
 1186 |       operator=(basic_fstream&& __rhs)
      |       ^~~~~~~~
C:/Program Files/mingw64/lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/fstream:1186:33: note: 
no known conversion for argument 1 from 'std::fstream*' {aka 'std::basic_fstream<char>*'} to 'st
d::basic_fstream<char>&&'
 1186 |       operator=(basic_fstream&& __rhs)
      |                 ~~~~~~~~~~~~~~~~^~~~~

I don't figure out how to solve this issue. What am I missing? If I explained myself badly, please tell me in the comments and I'll edit the question.


Solution

  • The function signature

    void openSourceOutputFiles(string sourceFilename, string outputFilename,
                               fstream *source, fstream *output){
    

    is wrong, because the parameter source is a copy of the global variable source. This means that any modification to the parameter source will not change the original global variable source.

    If you want to modify the original variable instead of the local parameter, you can either

    Since you are using pointers, I assume that you prefer a pointer solution, although the reference solution is more idiomatic to C++.

    In order to solve the problem using pointers, you can change the function signature to the following:

    void openSourceOutputFiles(string sourceFilename, string outputFilename,
                               fstream **source, fstream **output){
    

    In the function main, you must also change the line

    openSourceOutputFiles(sourceFilename, outputFilename, *source, *output);
    

    to

    openSourceOutputFiles(sourceFilename, outputFilename, &source, &output);
    

    in order to pass pointers to the source and output variables.

    After making these changes, your program will compile. However, it will be invoking undefined behavior if you ever use the fstream objects in the function main, because the fstream objects that are local to the function openSourceOutputFiles will cease to exist as soon as the function returns. This means that the two fstream * objects are dangling pointers, so that the pointers are effectively useless.

    In order to fix this, you can increase the lifetime of the objects by using dynamic memory allocation, by changing the lines

    fstream sourceFile(sourceFilename);
    fstream outputFile(outputFilename);
    
    *source = &sourceFile;
    *output = &outputFile;
    

    to:

    *source = new fstream(sourceFilename);
    *output = new fstream(outputFilename);
    

    However, this will require you to call the delete operator on these pointers, as soon as you no longer need them. Otherwise, you will have a memory leak.

    After making these changes, your code would look like this:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    string sourceFilename, outputFilename;
    string sourceContent, outputContent;
    fstream *source, *output;
    
    void getSourceOutputFiles(string *source, string *output) {
        cout << "Source ";
        cin >> *source;
        cout << "Output ";
        cin >> *output;
    }
    
    void openSourceOutputFiles(string sourceFilename, string outputFilename,
                               fstream **source, fstream **output){
        *source = new fstream(sourceFilename);
        *output = new fstream(outputFilename);
    }
    
    int main() {
        getSourceOutputFiles(&sourceFilename, &outputFilename);
        openSourceOutputFiles(sourceFilename, outputFilename, &source, &output);
    
        delete source;
        delete output;
    
        return 0;
    }
    

    This is the quickest way of fixing your immediate problem. However, as pointed out in the other answer, your approach is not the ideal way of solving the problem.

    It is worth noting that in modern C++, using raw pointers is not idiomatic. Smart pointers are generally used instead, so one would normally use make_unique instead of the new operator for allocating memory for the fstream objects.