Sqeaky
Sqeaky

Reputation: 1936

Safest way to extract from stream to char array or std::string

I am concerned about buffer overflows, and I need to get some characters out of a class that derives from std::istream. From what I understand there is no way to stream to an std::string directly from an istream, without my own >> operator. So I was considering streaming the contents to a char array, then putting that into a std::string. Here is a simple example:

char CharArray[1000] = {0};
SomeIStream >> CharArray;
std::string StuffFromStream(CharArray);

However, there seems to be no way to know that CharArray will not be overflowed. Is there some maximum the stream extraction operator will write to chararray? Is there some way to check how much will be extracted preemptively? Is this just all wrong, Is there some way that is much better than this?

Edit1:, I fixed my not a memory leak. No need to call delete. I can't believe I did that.

Edit2: The suggestion to use the >> directly to string was suggested. I attempted that previous in the code base this problem came from and it failed. Saying that no suitable match for the operator could be found. I then tried with an std::fstream and it failed again. Trying the std::fstream code in simple minimalistic project succeeded. This tells me that something else is wrong with my larger project. The original intent of this question is no longer valid.

Edit3: I solved this. I was attempted to stream to a typedef String, which I thought was actually and std::string, but it was really a const std::String. Naturally there isn't a stream extraction operator for writing to an unwritable object, so it just gave me all the operators listed in the istream header (the one I needed was in the string header).

Thanks to the people who pointed out my faulty research and pointe me in the right direction.

Upvotes: 1

Views: 12082

Answers (5)

Arunmu
Arunmu

Reputation: 6901

This is what my approach usually is (from "Thinking in C++" by Bruce Eckel)::

ifstream in("somefile.txt",ios::in);
istreambuf_iterator istr(in),end;
string str;
insert_iterator ins(str,str.begin());

while(istr != end){
      *ins++ = *istr++;
}

In the above code the whole file is taken as a character stream and then put into a string. This is shown just as an example.

Upvotes: 0

Éric Malenfant
Éric Malenfant

Reputation: 14148

If you want to read the whole stream into a string, this is not terribly efficient, but is safe:

std::string str((std::istream_iterator<char>(some_istream)), std::istream_iterator<char>());

(note the extra parenthesis, to avoid the most-vexing-parse)

If you want to read up to "n" characters:

some_istream.read(some_char_array, sizeof(some_char_array));

note that this won't null-terminate the array. Pass sizeof(char_array) - 1 instead if you want to leave the array's last char untouched.

Upvotes: 1

John Dibling
John Dibling

Reputation: 101506

Mixing old-school C-style char arrays with streams? Seems like some very confused code.

Commentary aside, just extract directly to a string. You can pass that (via the c_str() method) to C-style APIs that expect const char* parameters. And if for some bizarre reason you really do nead a char array, you can copy from the string to the char array safely, after checking bounds.

By the way, you've pretty clearly illustrated the main way in which magic numbers are evil. In your case, the magic number in question is 1000. You have no idea that 1000 is appropriate -- not too big, not too small -- without totally guessing. In programming, guessing often == crashing. Or even worse, not crashing.

By the way 2, you are deleteing an automatic variable above. You don't do this. Use delete if and only if you use new. You didn't new, so don't delete.

By the way 3, if you just want to extract the whole stream in to a string, you can just do this:

string s = SomeIStream.str();

Upvotes: 1

Steve M
Steve M

Reputation: 8526

If you've (properly) inherited from std::istream, then you don't need to do anything special and can just use operator >> (std::istream&, std::string&).

std::string s;
SomeIStream >> s;

When I say "properly," I mean overridden the appropriate virtual functions from istream.

"I know that if there is an exception before the delete this will leak memory." No it won't. You didn't allocate CharArray with new; calling delete on it will not do what you want.

Upvotes: 3

Puppy
Puppy

Reputation: 147036

All streams offer the .str() method, which will provide a copy of their buffer as a std::string (or wstring or whatever for other typedefs).

Also, you declared an array on the stack and then tried to delete it, which is UB.

Upvotes: 0

Related Questions