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.
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
fstream **
), orfstream *&
).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.