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

  • Even if you fix the syntax issue mentions in a comment below this answer (* is incorrect), it doesn't "work" because you are trying to return pointers to local variables whose lifetimes end when the function returns. You are then using dangling references in the caller.

    I'm writing a function in C++ that has to return more than one value, and I know that I can't.

    You absolutely can:

    auto openSourceOutputFiles(std::string sourceFilename, std::string outputFilename){
        std::fstream sourceFile(sourceFilename);
        std::fstream outputFile(outputFilename);
    
        return std::make_tuple(std::move(sourceFile), std::move(outputFile));
    }
    
    //caller:
    auto [sourceFile, outputFile] = openSourceOutputFiles(/*...*/);
    

    However, if this is not a one-of use, it is a better idea to use a structure with names instead of a tuple, so that the caller can identify what each item represents:

    auto openSourceOutputFiles(string sourceFilename, string outputFilename){
        struct Result {
            std::fstream sourceFile;
            std::fstream outputFile;
        };
    
        std::fstream sourceFile(sourceFilename);
        std::fstream outputFile(outputFilename);
    
        return Result{std::move(sourceFile), std::move(outputFile)};
    }
    

    Caller site can remain unchanged, but can also do

    auto files = openSourceOutputFiles(/*...*/);
    

    and then access files.sourceFile and files.outputFile.