I have a program where I attempt to take a string value out of a vector and convert it into a float. The string is guaranteed to be a numerical value based on how I'm parsing the input data. When I attempt to run my program, I get the following error.
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stof: no conversion
Abort trap: 6
I traced where the issue was coming from, and it was where I was calling stof() to convert the obtained value from the vector into a float. The issue also persists when I call stoi() on the values as well. I used a typeid call to verify the value and dumped the type to the console.
type of there_list[2]: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
val of there_list[2]: 10
I have absolutely no idea why this is the case, or what this even is for that matter, as my vector is clearly a vector of strings.
The code in question is the following:
string there(buffer);
vector<string> there_list = parse_word_list(there);
// Decide where to send the message next
// if the intended recipient (who the message is addressed to) is in range, send directly to recipient
cout << "type of there_list[2]: " << typeid(there_list[2]).name() << endl;
cout << "val of there_list[2]: " << there_list[2] << endl;
float dist_to_recipient = distance(sensor.getX(), sensor.getY(), stof(there_list[2]), stof(there_list[3]));
where buffer is a char[] that was used to read in input data from a server. My parse_word_list(there) call returns a string vector of the "words" contained in there delimited by spaces.
The function is basic, and looks like this
vector<string> parse_word_list(string phrase){
istringstream parse(phrase);
vector<string> word_list;
// Traverse through all words
do {
// Read a word
string word;
parse >> word;
// Append the read word to the word_list
word_list.push_back(word);
} while(parse); // While there is more to read
return word_list;
}
Related
In C++ when you use getline() with delimiter on stringstream there are few things that I didn't found documented, but they have some non-error handy behaviour when:
delimiter is not found => then simply whole string/rest of it is returned
there is delimiter but nothing before it => empty string is returned
getting something that isn't really there => returns the last thing that could be read with it
Some test code (simplified):
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string test(const string &s, char delim, int parseIndex ){
stringstream ss(s);
string parsedStr = "";
for( int i = 0; i < (parseIndex+1); i++ ) getline(ss, parsedStr, delim);
return parsedStr;
}
int main() {
stringstream ss("something without delimiter");
string s1;
getline(ss,s1,';');
cout << "'" << s1 << "'" << endl; //no delim
cout << endl;
string s2 = "321;;123";
cout << "'" << test(s2,';',0) << "'" << endl; //classic
cout << "'" << test(s2,';',1) << "'" << endl; //nothing before
cout << "'" << test(s2,';',2) << "'" << endl; //no delim at the end
cout << "'" << test(s2,';',3) << "'" << endl; //this shouldn't be there
cout << endl;
return 0;
}
Test code output:
'something without delimiter'
'321'
''
'123'
'123'
Test code fiddle: http://ideone.com/ZAuydR
The Question
The question is - can this be relied on? If so, where is it documented - is it?
Thanks for answers and clarifying :)
The behavior of getline is explicitly documented in the standard (C++11 §21.4.8.9 ¶7-10), which is the only normative document about C++.
The behavior your asked about in the first two questions is guaranteed, while the third one is a consequence of how your test rig is made.
template<class charT, class traits, class Allocator>
basic_istream<charT,traits>&
getline(basic_istream<charT,traits>& is,
basic_string<charT,traits,Allocator>& str,
charT delim);
template<class charT, class traits, class Allocator>
basic_istream<charT,traits>&
getline(basic_istream<charT,traits>&& is,
basic_string<charT,traits,Allocator>& str,
charT delim);
Effects: Behaves as an unformatted input function (27.7.2.3), except that it does not affect the value
returned by subsequent calls to basic_istream<>::gcount(). After constructing a sentry object,
if the sentry converts to true, calls str.erase() and then extracts characters from is and appends
them to str as if by calling str.append(1, c) until any of the following occurs:
end-of-file occurs on the input sequence (in which case, the getline function calls is.setstate(ios_base::eofbit)).
traits::eq(c, delim) for the next available input character c (in which case, c is extracted but
not appended) (27.5.5.4)
str.max_size() characters are stored (in which case, the function calls is.setstate(ios_base::failbit)) (27.5.5.4)
The conditions are tested in the order shown. In any case, after the last character is extracted, the
sentry object k is destroyed.
If the function extracts no characters, it calls is.setstate(ios_base::failbit) which may throw
ios_base::failure (27.5.5.4).
Returns: is.
Coming to your questions:
delimiter is not found => then simply whole string/rest of it is returned
That's a consequence of the first exit condition - when the input string terminates the string stream goes in end-of-file, so the extraction terminates (after having added all the preceding characters to the output string).
there is delimiter but nothing before it => empty string is returned
That's just a special case of the second point - the extraction terminates when the delimiter is found (traits::eq(c, delim) normally boils down to c==delim), even if no other character has been extracted before.
getting something that isn't really there => returns the last thing that could be read with it
It doesn't go exactly like this. If the stream is in an error condition (the sentry object does not convert to true, in the description above) - in your case you have an EOF -, getline leaves your string alone and returns. In your test code you see the last read data just because you are recycling the same string without clearing it between the various tests.
The behavior of C++ facilities is described by the ISO C++ standard. But, it's not the most readable resource. In this case, cppreference.com has good coverage.
Here's what they have to say. The quote blocks are copy-pasted; I've interspersed explanations to your questions.
Behaves as UnformattedInputFunction, except that input.gcount() is not affected. After constructing and checking the sentry object, performs the following:
"Constructing and checking the sentry" means that if an error condition has been detected on the stream, the function will return without doing anything. This is why in #3 you observe the last valid input when "nothing should be there."
1) Calls str.erase()
So, if nothing is subsequently found before the delimiter, you'll get an empty string.
2) Extracts characters from input and appends them to str until one of the following occurs (checked in the order listed)
a) end-of-file condition on input, in which case, getline sets eofbit.
This is an error condition which causes the string local variable to be unchanged by subsequent getlines.
It also allows you to observe the last segment of input before the end, so you may treat the end-of-file as a delimiter if you wish.
b) the next available input character is delim, as tested by Traits::eq(c, delim), in which case the delimiter character is extracted from input, but is not appended to str.
c) str.max_size() characters have been stored, in which case getline sets failbit and returns.
3) If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.
Currently I only know of two methods to insert values into a C++ string or C string.
The first method I know of is to use std::sprintf() and a C-string buffer (char array).
The second method is to use something like "value of i: " + to_string(value) + "\n".
However, the first one needs the creation of a buffer, which leads to more code if you just want to pass a string to a function. The second one produces long lines of code, where a string gets interrupted every time a value is inserted, which makes the code harder to read.
From Python I know the format() function, which is used like this:
"Value of i: {}\n".format(i)
The braces are replaced by the value in format, and further .format()'s can be appended.
I really like Python's approach on this, because the string stays readable, and no extra buffer needs to be created. Is there any similar way of doing this in C++?
Idiomatic way of formatting data in C++ is with output streams (std::ostream reference). If you want the formatted output to end up in a std::string, use an output string stream:
ostringstream res;
res << "Value of i: " << i << "\n";
Use str() member function to harvest the resultant string:
std::string s = res.str();
This matches the approach of formatting data for output:
cout << "Value of i: " << i << "\n";
This is my code:
StockAccount::StockAccount() {
vector<string> temp;
string line;
std::ifstream stockfile("Results.txt");
if (stockfile.is_open()) {
while (stockfile.good()) {
getline(stockfile, line);
istringstream ss(line);
string token;
while (std::getline(ss, token, ',')) {
temp.push_back(token);
}
addStock(temp.at(0), temp.at(1), temp.at(2));
temp.clear();
}
stockfile.close();
} else {
cout << "Unable to open file" << std::endl << std::endl;
}
}
I know it isn't THAT efficient, that is what I am trying to fix. What it is supposed to be doing is:
Read that file line by line.
Parse each line and split it by comma.
Take those 3 values and use it in a method.
I am using that vector temp to store the values, add them to the function and then clear it so that it can be empty and used again to store the next ones ...etc.
I tried printing out each value BEFORE the temp.clear() and they all print out and THEN I get the error. So I know that temp.clear() is the problem. Perhaps I am using the wrong method, or there is a much better way.
I want to try and NOT use boost if possible.
This is the error I'm getting:
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: vector
Results.txt is a file that looks like.
goog,525,0
msft,34,10
and so on.
while (stockfile.good()) is wrong, and leads to your reading one extra, non-existent line.
That's because you're checking for stream validity before attempting to read a new line; if there's no new line to read, it's only after the call to getline that this condition would evaluate to false but by then it's too late and you're off trying to handle this non-existent line.
That non-existent line does not have three tokens on it, but you are performing no error checking on the tokenization, nor are you ever verifying the size of the vector temp.
So, when you come to try to access those three vector elements, which don't exist, an exception is thrown.
Your loop should look like this:
while (getline(stockfile, line)) {
istringstream ss(line);
string token;
// ...
}
Notice how I directly check for success in the loop condition, which will prevent the loop body from being executed if the actual getline fails.
I'm trying to store strings directly into a file to be read later in C++ (basically for the full scope I'm trying to store an object array with string variables in a file, and those string variables will be read through something like object[0].string). However, everytime I try to read the string variables the system gives me a jumbled up error. The following codes are a basic part of what I'm trying.
#include <iostream>
#include <fstream>
using namespace std;
/*
//this is run first to create the file and store the string
int main(){
string reed;
reed = "sees";
ofstream ofs("filrsee.txt", ios::out|ios::binary);
ofs.write(reinterpret_cast<char*>(&reed), sizeof(reed));
ofs.close();
}*/
//this is run after that to open the file and read the string
int main(){
string ghhh;
ifstream ifs("filrsee.txt", ios::in|ios::binary);
ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));
cout<<ghhh;
ifs.close();
return 0;
}
The second part is where things go haywire when I try to read it.
Sorry if it's been asked before, I've taken a look around for similar questions but most of them are a bit different from what I'm trying to do or I don't really understand what they're trying to do (still quite new to this).
What am I doing wrong?
You are reading from a file and trying to put the data in the string structure itself, overwriting it, which is plain wrong.
As it can be verified at http://www.cplusplus.com/reference/iostream/istream/read/ , the types you used were wrong, and you know it because you had to force the std::string into a char * using a reinterpret_cast.
C++ Hint: using a reinterpret_cast in C++ is (almost) always a sign you did something wrong.
Why is it so complicated to read a file?
A long time ago, reading a file was easy. In some Basic-like language, you used the function LOAD, and voilà!, you had your file.
So why can't we do it now?
Because you don't know what's in a file.
It could be a string.
It could be a serialized array of structs with raw data dumped from memory.
It could even be a live stream, that is, a file which is appended continuously (a log file, the stdin, whatever).
You could want to read the data word by word
... or line by line...
Or the file is so large it doesn't fit in a string, so you want to read it by parts.
etc..
The more generic solution is to read the file (thus, in C++, a fstream), byte per byte using the function get (see http://www.cplusplus.com/reference/iostream/istream/get/), and do yourself the operation to transform it into the type you expect, and stopping at EOF.
The std::isteam interface have all the functions you need to read the file in different ways (see http://www.cplusplus.com/reference/iostream/istream/), and even then, there is an additional non-member function for the std::string to read a file until a delimiter is found (usually "\n", but it could be anything, see http://www.cplusplus.com/reference/string/getline/)
But I want a "load" function for a std::string!!!
Ok, I get it.
We assume that what you put in the file is the content of a std::string, but keeping it compatible with a C-style string, that is, the \0 character marks the end of the string (if not, we would need to load the file until reaching the EOF).
And we assume you want the whole file content fully loaded once the function loadFile returns.
So, here's the loadFile function:
#include <iostream>
#include <fstream>
#include <string>
bool loadFile(const std::string & p_name, std::string & p_content)
{
// We create the file object, saying I want to read it
std::fstream file(p_name.c_str(), std::fstream::in) ;
// We verify if the file was successfully opened
if(file.is_open())
{
// We use the standard getline function to read the file into
// a std::string, stoping only at "\0"
std::getline(file, p_content, '\0') ;
// We return the success of the operation
return ! file.bad() ;
}
// The file was not successfully opened, so returning false
return false ;
}
If you are using a C++11 enabled compiler, you can add this overloaded function, which will cost you nothing (while in C++03, baring optimizations, it could have cost you a temporary object):
std::string loadFile(const std::string & p_name)
{
std::string content ;
loadFile(p_name, content) ;
return content ;
}
Now, for completeness' sake, I wrote the corresponding saveFile function:
bool saveFile(const std::string & p_name, const std::string & p_content)
{
std::fstream file(p_name.c_str(), std::fstream::out) ;
if(file.is_open())
{
file.write(p_content.c_str(), p_content.length()) ;
return ! file.bad() ;
}
return false ;
}
And here, the "main" I used to test those functions:
int main()
{
const std::string name(".//myFile.txt") ;
const std::string content("AAA BBB CCC\nDDD EEE FFF\n\n") ;
{
const bool success = saveFile(name, content) ;
std::cout << "saveFile(\"" << name << "\", \"" << content << "\")\n\n"
<< "result is: " << success << "\n" ;
}
{
std::string myContent ;
const bool success = loadFile(name, myContent) ;
std::cout << "loadFile(\"" << name << "\", \"" << content << "\")\n\n"
<< "result is: " << success << "\n"
<< "content is: [" << myContent << "]\n"
<< "content ok is: " << (myContent == content)<< "\n" ;
}
}
More?
If you want to do more than that, then you will need to explore the C++ IOStreams library API, at http://www.cplusplus.com/reference/iostream/
You can't use std::istream::read() to read into a std::string object. What you could do is to determine the size of the file, create a string of suitable size, and read the data into the string's character array:
std::string str;
std::ifstream file("whatever");
std::string::size_type size = determine_size_of(file);
str.resize(size);
file.read(&str[0], size);
The tricky bit is determining the size the string should have. Given that the character sequence may get translated while reading, e.g., because line end sequences are transformed, this pretty much amounts to reading the string in the general case. Thus, I would recommend against doing it this way. Instead, I would read the string using something like this:
std::string str;
std::ifstream file("whatever");
if (std::getline(file, str, '\0')) {
...
}
This works OK for text strings and is about as fast as it gets on most systems. If the file can contain null characters, e.g., because it contains binary data, this doesn't quite work. If this is the case, I'd use an intermediate std::ostringstream:
std::ostringstream out;
std::ifstream file("whatever");
out << file.rdbuf();
std::string str = out.str();
A string object is not a mere char array, the line
ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));
is probably the root of your problems.
try applying the following changes:
char[BUFF_LEN] ghhh;
....
ifs.read(ghhh, BUFF_LEN);
I am new to C++ (coming from a C# background) and am trying to learn how to convert a string to an int.
I got it working by using a stringstream and outputting it into a double, like so:
const char* inputIndex = "5+2";
double number = 0;
stringstream ss(inputIndex);
ss >> number;
// number = 5
This works great. The problem I'm having is that the strings I'm parsing start with a number, but may have other, not digit characters after the digits (e.g. "5+2", "9-(3+2)", etc). The stringstream parses the digits at the beginning and stops when it encounters a non-digit, like I need it to.
The problem comes when I want to know how many characters were used to parse into the number. For example, if I parse 25+2, I want to know that two characters were used to parse 25, so that I can advance the string pointer.
So far, I got it working by clearing the stringstream, inputting the parsed number back into it, and reading the length of the resulting string:
ss.str("");
ss << number;
inputIndex += ss.str().length();
While this does work, it seems really hacky to me (though that might just be because I'm coming from something like C#), and I have a feeling that might cause a memory leak because the str() creates a copy of the string.
Is there any other way to do this, or should I stick with what I have?
Thanks.
You can use std::stringstream::tellg() to find out the current get position in the input stream. Store this value in a variable before you extract from the stream. Then get the position again after you extract from the stream. The difference between these two values is the number of characters extracted.
double x = 3435;
std::stringstream ss;
ss << x;
double y;
std::streampos pos = ss.tellg();
ss >> y;
std::cout << (ss.tellg() - pos) << " characters extracted" << std::endl;
The solution above using tellg() will fail on modern compilers (such as gcc-4.6).
The reason for this is that tellg() really shows the position of the cursor, which is now out of scope. See eg "file stream tellg/tellp and gcc-4.6 is this a bug?"
Therefore you need to also test for eof() (meaning the entire input was consumed).