Cannot make std::unique_ptr<std::istream> hold a pointer to std::ifstream - c++

Consider the following piece of code (out of context for the sake of simplicity):
std::unique_ptr<std::istream> stream;
stream = std::make_unique<std::ifstream>(path, std::ios::in | std::ios::binary);
This code compiles just fine with MSVC and works with no problem, but Clang issues an error:
error: no viable overloaded '='
stream = std::make_unique<std::ifstream>(path, std::ios::in | std::ios::binary);
Alongside with the error above, the log also claims that 'unique_ptr<std::basic_ifstream<char>, default_delete<std::basic_ifstream<char>>>' is not convertable to 'unique_ptr<std::istream, default_delete<std::istream>>'.
I cannot use a reference as I need to keep stream alive outside the current scope, so a pointer seems to be the only solution. How can I solve the problem?

Related

Passing a string argument to ifstream

I'm trying to pass a string argument to a function from the main function and then passing this received string argument to ifstream constructor. I'm able to receive this string in the function, but when I pass this argument to ifstream, I get a error message:
no matching function for call to ‘std::basic_ifstream::basic_ifstream(const string&)’
std::ifstream file(fileName);
Here is my code:
int** read_CSV(std::string const& fileName)
{
//cout<<fileName<<"\n";//this works
std::ifstream file(fileName);//problem
//Rest of logic
}
The main function:
int main()
{
int** inputMatrix1 = read_CSV("inputData4_80-20_100x32.csv");
return 0;
}
The variable fileName is creating the problem. If I pass it as it is, it gives the error. But instead, if I explicitly mention the name of the file using string rather than the variable, the code works fine. Can someone explain what exactly is the problem here and how I can solve it?
Okay, so the problem was that I was trying to compile without C++11 standard using just g++ "NameOfFile.cpp". There are 2 possible solutions to the problem, from the comment section, and they are as follows:
Using -std=c++11 when giving the command for compilation. The resultant compilation command would look as follows:
g++ -std=c++11 "NameOfFile.cpp"
Another solution, as pointed out by #Peter, is to use c_str() at the end of the string object, since the ifstream doesn't accept strings as an argument before c++11, so c_str() is used for explicitly converting to a compatible format.
Here's the modified code line for the second solution:
std::ifstream file(fileName.c_str());
Thanks to #Peter and #Holt for their inputs.

Why can an `ifstream` be opened both for reading and writing?

I've seen an interesting piece of code today:
ifstream fil;
fil.open( "ini.txt", std::ios::in | std::ios::out );
I was just about to rant about its brokenness, but to my astonishement I saw that cppreference.com apparently thinks this is correct:
http://en.cppreference.com/w/cpp/io/basic_ifstream/open
mode - specifies stream open mode. It is bitmask type, the following constants are defined:
in: open for reading
out: open for writing
How can an ifstream, which, as far as I understand is an INPUT file stream, be opened both for reading and writing?
Shouldn't it necessarily be fstream instead of ifstream?
std::ifstream is like a handle over a std::basic_filebuf. You can even access that buffer from the handle with a call to std::basic_ifstream::rdbuf.
You can steal that buffer from the handle, and assign it to another (I won't go into how it's done). And here's the interesting thing. You can move that very buffer from an ifstream to an ofstream. And that requires being able to open the buffer for writing. As such, the very same reference page you linked says this:
Effectively calls rdbuf()->open(filename, mode | ios_base::in)
This is a convenience function to avoid manipulating the buffer itself later.
you need to use fstream:
fstream file("input.txt", ios::in | ios::out | ios::app);
int data;
file >> data;
file << data +1;
file.close();

C++ Writing to file vector of byte

I have:
typedef unsigned char;
std::vector<byte> data;
I tried to save data in file this way (but I have error):
fstream file(filename,ios::out);
file.write(&data, data.size());
How to process or cast data to write it in file.
To store a vector in a file, you have to write the contents of the vector, not the vector itself. You can access the raw data with &vector[0], address of the first element (given it contains at least one element).
ofstream outfile(filename, ios::out | ios::binary);
outfile.write(&data[0], data.size());
This should be fairly efficient at writing. fstream is generic, use ofstream if you are going to write.
*Statement file.write(&buffer[0],buffer.size()) makes error:
error C2664: 'std::basic_ostream<_Elem,_Traits>::write' : cannot
convert parameter 1 from 'unsigned char *' to 'const char *'
*In my compiler (VS2008) I don't have data() method for vector.
I think below is correct:
file.write((const char*)&buffer[0],buffer.size());
Use vector::data to get a pointer the the underlying data:
file.write(data.data(), data.size());
You are to pass the address of the first element, not the address of the vector object itself.
&data[0]
Note: Make sure that the vector is not empty before doing this.
A lot of these solutions are only partially complete (lacking includes & casts), so let me post a full working example:
#include <vector>
#include <fstream>
int main()
{
std::vector<std::byte> dataVector(10, std::byte{ 'Z' });
const std::string filename = "C:\\test_file.txt";
std::ofstream outfile(filename, std::ios::out | std::ios::binary);
outfile.write(reinterpret_cast<const char*>(dataVector.data()), dataVector.size());
return 0;
}
I think that ostream.write (myVector[0], ...) will not work, as it does not work in reading into vector (that I had.)
What works is ostream.write(MyVector.data(), ...)
Note: for reading use ifstream.read(const_cast(MyVector.data()), ...)

How can I use fread() on a binary file to read the data into a std::vector?

Follow-up question on an earlier question I had, that has been perfectly answered. To quickly recap, I had trouble creating a class holding a huge array (stack overflow error). In the answers, some users recommended I use std::vector instead.
The function to read in the data looks like this:
Test()
{
memset(myarray, 0, sizeof(myarray));
FILE* fstr = fopen("myfile.dat", "rb");
size_t success= fread(myarray, sizeof(myarray), 1, fstr);
fclose(fstr);
}
for a myarray which looked like this:
int myarray[45000000];
My question is: How can I read this into a preferable:
std::vector<int> myvector;
I searched google , and have found multiple answers, usually pointing to the following code:
std::ifstream input("myfile.dat", std::ios::in | std::ifstream::binary);
std::copy(std::istream_iterator<int>(input),
std::istream_iterator<int>(),
std::back_inserter(myvector));
After implementing this, and when calling myvector.size() I get 16 (for whatever reason), and accessing a vector element leads to an immediate crash for going out of the vector bounds.
So what do I have to do to get this right? I once read somewhere that I could just simply use the "old" method, and then reading the array into the vector, but this seems to defeat the purpose of using the vector in the first place.
fread() reads your file binary, while ifstream_iterator tries to extract formatted ints (like 42).
You want to resize your vector and use input.read(...) instead:
const size_t size = 45000000; // change this to the appropriate value
std::vector<char> myvector(size, 0);
std::ifstream input("myfile.dat", std::ios::in | std::ifstream::binary);
input.read(&myvector[0], myvector.size());
Note that you need to use a std::vector<char> since read expects the first parameter to be a char *. You can use other types T if you cast the type correctly:
input.read(reinterpret_cast<char*>(&myvector[0]), myvector.size() * sizeof(T));
If you're using C++ you should try to avoid using the C FILE APIs all together -- so you're on the right track. The problem you're having is that istream_iterator reads input as text, not binary -- it's expecting ASCII digits. This this out instead:
std::vector<int> vec(45000000);
std::filebuf fb;
fb.open("myfile.dat", std::ios_base::in | std::ios_base::binary);
fb.sgetn((char*)&vec[0], vec.size() * sizeof(vec[0]));

Is ios::in needed for ifstream's opened in binary mode?

What's the difference between these two? Isn't the in flag object thing redundant? Thanks.
std::ifstream file1("one.bin", std::ifstream::in | std::ifstream::binary);
std::ifstream file2("two.bin", std::ifstream::binary);
From the docs on ifstream class constructor:
binary (binary) Consider stream as binary rather than text.
in (input) Allow input operations on the stream.
So when reading from a file, I would use std::ifstream::in flag not because it's required (or not) but because it would be a good programming practice to let a programming interface know what you are going to use it for.
Edit:
The following is taken from http://www.cplusplus.com/doc/tutorial/files/, about open() member function though (but the constructors in the code in the question probably call open() copying the mode flags without modification).
class: default mode parameter
ofstream: ios::out
ifstream: ios::in
fstream: ios::in | ios::out
For ifstream and ofstream classes, ios::in and ios::out are
automatically and respectively assumed, even if a mode that does not
include them is passed as second argument to the open() member
function.
Nevertheless, many examples over the Web use ifstream::in when showing a construction of an ifstream object. Could really be some kind of a superstition practice, instead of a programming one.
binary, in this case, only refers to the method of reading or writing. In regular mode on windows, '\n' is translated to '\r''\n'. This can affect both reading and writing, so binary mode turns this off. out|binary makes just as much sense as in|binary
I can't find authoritative documentation online.
Edit I can't even find a proper reference in my copy the Josuttis Book, 8th printing. It should have been in section 13.9 pp. 627-631
Empirical evidence suggests it is redundant IFF none of std::ios::in or std::ios:out are passed:
#include <fstream>
#include <iostream>
int main(int argc, char** args)
{
std::ifstream ifs(args[0], std::ios::binary);
std::cout << ifs.rdbuf() << std::flush;
return 0;
}
Succeeds:
test | md5sum
md5sum test
show the same hash sum.
// ...
std::ifstream ifs(args[0], std::ios::out | std::ios::binary);
will fail (zero bytes output)
test | wc -c # shows 0
From cplusplus.com reference page, there is no difference.
in is always set for ifstream objects (even if explicitly not set in argument mode).
It's the same for ofstream. Therefore, you don't need to set std::ios::in for ifstream or std::ios::out for ofstream, even if you have set std::ios::binary which omits the in/out mode.