Reference to an fstream object creating an error - c++

I'm getting an error running a program that demonstrates how file stream objects may be passed by reference to functions. The program fails when making a call to the file.open(name, ios::in) function:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
//function prototypes
bool openFileIn(fstream &, string);
void showContents(fstream &);
int main(){
fstream dataFile;
if (openFileIn(dataFile, "demofile.txt"))
{
cout << "File opened successfully.\n";
cout << "Now reding data from the file. \n\n";
showContents(dataFile);
dataFile.close();
cout << "\nDone. \n";
}
else
cout <<"File open error! "<< endl;
return 0;
}
//******************************************************************
//Definition of function openFileIn. Accepts a reference to an
//fstream object as an argument. The file is opened for input.
//The function returns true upon success, false upon failure.
//******************************************************************
bool openFileIn(fstream& file, string name)
{
file.open(name, ios::in); //error occurs here
if (file.fail())
return false;
else
return true;
}
//*******************************************************************
//Defintion of function showContents. Accepts an fstream reference
//as its argument. Uses a loop to read each name from the file and
//displays it on the screen.
//*******************************************************************
void showContents(fstream &file)
{
string line;
while(file >> line)
{
cout << line << endl;
}
}
The error occurs in the 'openFileIn()' function. The 'file.open()' call fails with an error.
Here is the stacktrace:

The open function overload taking std::string as parameter, is defined starting from C++11.
You are likely to be using an old compiler, so you need to use the old open signature using const char *.
Try:
file.open(name.c_str(), ios::in);
I'm getting an error running a program that demonstrates how file
stream objects may be passed by reference to functions. The program
fails when making a call to the file.open(name, ios::in) function
Note that your program is not compiling at all. What you see in the output is a compiling error, not a stacktrace.

Related

MYSTERY IN C++: Function call misbehaving just because of the presence of another function call even though they are unrelated

My program searches for a string in a file, return the line number and then copy all lines of the file just before the line number of the searched string, into another file. But to my greatest suprise, which I regard as a MYSTERY, is that;
when the searched string line number is passed to the file copy function, instead of copying all lines before the searched string line number as defined in the file copy function, it does the reverse
if i change to greater than in the file copy function i.e. such that it should copy all lines after the searched string line number, nothing is copied at all.
if instead i manually enter a line number in the file copy function i.e. not using the search string line number returned, same thing happens as in 1 and 2 above.
finally, if i remove the search string function and manually enter a line number into the copy file function, everything works fine in both direction i.e for copying lines before or after the line number.
Really, this is a MYSTERY. PLEASE WHO CAN HELP?
HERE IS THE PROGRAM
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <string>
std::ifstream fin;
std::ofstream fout;
void Copyfile(std::ifstream& in_stream, std::ofstream& out_stream, std::string Line,int searchstringline);
int searchString(std::ifstream& in_stream, std::string string1);
int main(){
fin.open("C++.txt");
if (fin.fail())
{
std::cout << "Output file opening failed.\n";
exit(1);
}
fout.open("Temp.txt",std::ios::app);
if (fin.fail())
{
std::cout << "Input file opening failed.\n";
fin.close();
exit(1);
}
int searchstringline;
searchstringline = searchString(fin, "main");
Copyfile(fin, fout, "line", searchstringline);
}
void Copyfile(std::ifstream& in_stream, std::ofstream& out_stream, std::string Line, int searchstringline){
int count = 0;
for (int i = 0; getline(fin,Line); i++){
count++;
while (count < searchstringline){
out_stream << Line << std::endl;
break;
}
}
}
int searchString(std::ifstream& in_stream, std::string string1){
std::string input;
int number = 0;
for (int i = 0; getline(fin, input); i++){
number++;
if (input.find(string1) != std::string::npos){
break;
}
}
return number;
}
The solution to the mystery is simply closing the file after calling the searchstring function and reopening it before calling the copyfile function. This is advisable generally whenever you have more than one function accessing a file in order to avoid distortion due to a function reflecting after another function is called to use the file.
Cheers!

Can I return an object of ofstream to initinialize another object of ofstream?

I would like to open a file in one function return the open file object to main, and use it another
function to populate the file. It appears the compiler is telling me that I"m trying to access a private member of iostream. Is there a way to do this and how?
ofstream& open_outfile()
{
string outfile;
cout << "Please enter the name of the file:";
cin >> outfile;
ofstream ost(outfile.c_str());
if (!ost) error("can't open out file");
return ost;
}
//...............
int main()
{
//...some code
ofstream ost = open_outfile();//attempt 1
//ofstream ost() = open_outfile();//attempt 2
populate_outfile(ost, readings);
keep_window_open();
}
This syntax which I found in "The c++ programming language" seems to work:
ofstream ost = move(open_outfile());
Which is better? Declaring the object in main and passing by reference ost to both function? Or using the move constructor?
The various stream classes have move constructors in C++11, i.e., you can move a std::ofstream from a function and initialize a std::ofstream from it (trying to initialize a std::ostream from an std::ofstream does not work). That is, assuming you compile with -std=c++11 and the versions of libstdc++ shipping with your version of gcc is updated to support these constructors.
You can pass in a reference to an ofstream object into the function:
void open_outfile(/*out*/ ofstream &ost)
{
string filename;
cout << "Please enter the name of the file:";
cin >> filename;
ost.open(filename.c_str());
if (!ost) error("can't open out file");
}
Then, in main:
int main()
{
ofstream ost;
open_outfile(ost);
populate_outfile(ost, readings);
keep_window_open();
}

Loop to check existence of file and process it

I am starting the first part of a school assignment and I must prompt the user to enter a filename, check for the existence of the file, and if it exists, open it for processing; otherwise I am to have the user enter another filename.
When I compile and run my program below, I get the error message "No file exists. Please enter another filename." When I type in names of files that don't exist it just runs the first part of my do while loop again. I'm a beginner at C++ but I've done this before and I feel as if it should be running properly. Any help would be appreciated.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct customerData
{
int _customerID;
string _firstName, _lastName;
double _payment1, _payment2, _payment3;
};
void processFile();
int main()
{
processFile();
system ("pause");
return 0;
}
void processFile()
{
string filename;
ifstream recordFile;
do
{
cout << "Please enter a filename\n";
cin >> filename;
recordFile.open(filename);
if (recordFile.good())
// {
// enter code for if file exists here
// }
;
}
while(recordFile.fail());
{
cout << "No file by that name. Please enter another filename\n";
cin >> filename;
recordFile.open(filename);
}
}
To check whether a file was successfully opened you must use the std::fstream::is_open() function, like so:
void processfile ()
{
string filename;
cout << "Please enter filename: ";
if (! (cin >> filename))
return;
ifstream file(filename.c_str());
if (!file.is_open())
{
cerr << "Cannot open file: " << filename << endl;
return;
}
// do something with open file
}
The member functions .good() and .fail() check for something else not whether the file was opened successfully.
I'm not 100% sure what your intent is here, but do you understand that you've only got one loop here? After your do/while loop, you've got some code in braces, but that's not connected to any loop construct... it's simply a new scope (which doesn't serve a purpose here).
So, your program does this:
1) Ask for filename. Try to open it. If file stream can be read, do the "enter code here" part.
2) Check if filestream is "bad". if so, go back to step 1. Otherwise, continue.
3) Print out "no file by that name", prompt for a new file, try to open it
That's almost certainly not what you want.
You can use c code.
FILE *fp = fopen("file" "r");
if(fp){
//do stuff
}
else{
//it doesnt exist
}
on a side note, when using namespace std try to make it not global
you can put it inside of your functions instead when necessary
int main(){
using namespace std;
//other std stuff
}

File I/0 Function what type of arguments does it take?

Hey i'm writing a game in C++ and i don't understand what type of arguments the save function takes. I assumed you would use the file name for the arguments but i just get an error.
4 IntelliSense: a reference of type "std::ofstream &" (not const-qualified) cannot be > initialized with a value of type "const
char [9]" c:\Users\Conor\Documents\College\C++
Programming\Marooned\Marooned\MainApp.cpp 13 13 Marooned
void MenuText::print()
{
cout<< "Story= " << mText<< endl;
cout<< endl;
}
void MenuText::save(ofstream& outFile)
{
outFile<< "Story = " << mText<< endl;
outFile<< endl;
}
void MenuText::load(ifstream& inFile)
{
string garbage;
inFile>> garbage >> mText;
}
Can anyone help me understand what type of arguments does it take?
It seems that you are calling the save function with a literal string (the filename I guess by the error message). You should call it with an existing ofstream instead.
Something like
MenuText menuText;
std::ofstream output("some file name");
menuText.save(output);
std::ofstream& is a reference to an output stream. So you need to pass in an ofstream (Output File stream): http://www.cplusplus.com/reference/iostream/ofstream/

Returning ifstream in a function

Here's probably a very noobish question for you: How (if at all possible) can I return an ifstream from a function?
Basically, I need to obtain the filename of a database from the user, and if the database with that filename does not exist, then I need to create that file for the user. I know how to do that, but only by asking the user to restart the program after creating the file. I wanted to avoid that inconvenience for the user if possible, but the function below does not compile in gcc:
ifstream getFile() {
string fileName;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> fileName;
ifstream first(fileName.c_str());
if(first.fail()) {
cout << "File " << fileName << " not found.\n";
first.close();
ofstream second(fileName.c_str());
cout << "File created.\n";
second.close();
ifstream third(fileName.c_str());
return third; //compiler error here
}
else
return first;
}
EDIT: sorry, forgot to tell you where and what the compiler error was:
main.cpp:45: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
EDIT: I changed the function to return a pointer instead as Remus suggested, and changed the line in main() to "ifstream database = *getFile()"; now I get this error again, but this time in the line in main():
main.cpp:27: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
No, not really. ifstream doesn't have a copy constructor, and if you try to return one, that means copying the instance in your function out to wherever the return needs to go.
The usual workaround is to pass in a reference to one, and modify that reference in your function.
Edit: while that will allow your code to work, it won't fix the basic problem. Right now, you're mixing two rather different responsibilities into a single function: 1) obtain a file name, 2) open or create that file. I think if you separate those, the code will be simpler, and make it much easier to eliminate the source of the problem you're seeing.
Edit 2: Using a reference like this works perfectly well without an operator=. The general idea is something like:
int open_file(char const *name, fstream &stream) {
stream.open(name);
}
The assignment operator is neither necessary nor useful in this case -- we simply use the existing fstream via the reference. An operator= would be necessary if and only if we had to pass the argument to the ctor. With a stream, we can default construct a stream that doesn't connect to a file, and then use open to connect to the file after the fact.
bool checkFileExistence(const string& filename)
{
ifstream f(filename.c_str());
return f.is_open();
}
string getFileName()
{
string filename;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> filename;
return filename;
}
void getFile(string filename, /*out*/ ifstream& file)
{
const bool file_exists = checkFileExistence(filename);
if (!file_exists) {
cout << "File " << filename << " not found." << endl;
filename = getFileName(); // poor style to reset input parameter though
ofstream dummy(filename.c_str();
if (!dummy.is_open()) {
cerr << "Could not create file." << endl;
return;
}
cout << "File created." << endl;
}
file.open(filename.c_str());
}
int main()
{
// ...
ifstream file;
getFile("filename.ext", file);
if (file.is_open()) {
// do any stuff with file
}
// ...
}
ifstream does not support copy construct semantics (that what the error message basically sais), so you cannot return an ifstream. Return an ifstream* instead, and pass to the caller the responsability to delete the allocate pointer.
As an option, ifstream may be extended and custom constructor added to new class.
I've extended it to create test resource stream, encapsulating test resource lookup inside of it.
// test_utils.h
class TestResourceStream : public std::ifstream {
public:
TestResourceStream(const char* file_path);
};
// test_utils.cpp
namespace fs = std::filesystem;
fs::path test_resource_path(const char* file_path) {
fs::path path{std::string{"tests/resources/"} + file_path};
if (!fs::exists(path))
throw std::runtime_error{std::string{"path "} +
fs::absolute(path).c_str() + " does not exist"};
return path;
}
TestResourceStream::TestResourceStream(const char* file_path)
:std::ifstream{test_resource_path(file_path).c_str()} {}
// usage in test
TEST_CASE("parse") {
std::list<GosDump::Expertise> expertises;
TestResourceStream stream("requests/page_response.json");
GosDump::Json::parse(expertises, stream);
REQUIRE(10 == expertises.size());
}