C++: Why does dereferencing this vector iterator segfault? - c++

void insert_string( std::vector<std::string> & strings, const std::string &s )
{
std::vector<std::string>::iterator it=lower_bound(strings.begin(),strings.end(),s);
if(strings.size()>0) std::cout<<*it<<" is found\n"; // ****
strings.insert(it,s);
}
When attempting to use this function, the first insertion goes fine. The second insertion will output "[firststring] is found" and then segfault. If I comment out the if/cout line, I can repeatedly call and no segfaults occur.
I've also tried doing something like std::string tmp=*it; which will then segfault on that line. While printing is not a huge deal, what I'm really trying to do is check if the string at the position found by lower_bound is the same as the string that is trying to be inserted (i.e., if(*it==s), which is segfaulting just like the above two examples).
What am I missing here?
Thanks!

Check for the condition if it == strings.end(), if it is don't print it. This could cause the issue. Are you sure the string you're trying to check is in the vector of strings?

Related

Converting from vector<string> to vector<double> without std::stod

It started with converting a vector<string> to vector<double>. I use gcc without C++11 so I could not use this approach. After having a look at the algorithm template of transpose I tried to use the template instead, but there is a bug for std::stod used inside the template (for gcc 4.x which results in ‘stod’ is not a member of ‘std’) So why not write it yourself and I use while-loop with stringstream (expensive?):
int i = 0;
while (svec.begin() != svec.end()) {
stringstream(*svec.begin())>> dvec[i] ;//svec: strings, dvec: doubles
//dvec[i] = std::stod(*svec.begin());
++svec.begin(); i++;
}
Unfortunately I get: double free or corruption (out): 0x00007f4788000ba0 ***
I think the issue here is that
++svec.begin();
doesn't work the way you think it does. This doesn't advance forward the beginning of the vector. Instead, it gets a (temporary) iterator to the beginning of the vector, then increments that. As a result, you'll be stuck in an infinite loop. To fix this, use a more traditional "loop over a container" loop either by using a range-based for loop or just counting up the indices.
I also noticed that you're writing into dvec by index. Without seeing the code to initialize dvec, I can't be sure of whether this is safe, since if you didn't already resize the vector this will write off the end and lead to undefined behavior. Even if you did set it up properly, because of the broken loop, my guess is that this eventually writes off the end of the vector and is what directly triggers the issue.
First of all, let's clear up some confusion:
std::stod is a C++11 function, so if you do not use C++11, then it is not a "bug" if it cannot be found.
You mean std::transform and not transpose, don't you?
You may very well use std::transform without C++11 and without std::stod. Unfortunately you don't show the code with which you tried.
So why not write it yourself and I use while-loop with stringstream
Yes, why not?
(expensive?):
Measure it :)
But it's unlikely you'll notice a difference.
int i = 0;
while (svec.begin() != svec.end()) {
The loop condition does not make sense. begin() and end() do not change. This line effectively reads as "do this stuff as long as the vector does not become empty".
stringstream(*svec.begin())>> dvec[i] ;//svec: strings, dvec: doubles
//dvec[i] = std::stod(*svec.begin());
++svec.begin(); i++;
}
I'd say you are overthinking this. The crash you get may come from the fact that you access dvec[i] while dvec is still empty, and you never actually add elements to it. That's undefined behaviour.
It's really as simple as "loop through string vector, use a stringstream on each element to get a double value, and add that value to the result vector", expressed in C++03 as:
// loop through string vector
for (std::vector<std::string>::const_iterator iter = svec.begin(); iter != svec.end(); ++iter)
{
std::string const& element = *iter;
// use a stringstream to get a double value:
std::istringstream is(element);
double result;
is >> result;
// add the double value to the result vector:
dvec.push_back(result);
}
If you don't have stod (which was added in C++11) you can use strtod and apply it to a C-string that corresponds to the C++ string that you have. Copying from the approach that you linked to and making that change (and cleaning up the formatting):
std::vector<double> convertStringVectortoDoubleVector(
const std::vector<std::string>& stringVector){
std::vector<double> doubleVector(stringVector.size());
std::transform(stringVector.begin(), stringVector.end(),
doubleVector.begin(), [](const std::string& val)
{
return strtod(val.c_str(), 0);
});
return doubleVector;
}
Note that if the code hasn't already ensured that each string holds a valid representation of a floating-point value you'll have to add code to check whether strtod succeeded.

Segmentation fault in std::transform

I'm trying to transfer parsed out the file names from regex match to the list of filesystem::path objects.
I believe that matches are valid because for_each for the same iterators and print to console work perfectly. However, I'm getting a segmentation fault running this code. What am I doing wrong? Is there a mistake in my lambda?
namespace fs = boost::filesystem;
std::forward_list<fs::path> results;
std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
std::sregex_iterator(), results.begin(),
[&](const std::smatch& m)->fs::path{
return root / fs::path(m[1].str());
});
GDB shows me this line as a place of error:
path& operator=(const path& p)
{
m_pathname = p.m_pathname;
return *this;
}
UPDATE: found the solution - use back_inserter(results) instead of results.begin(). However, why is that?
The std::transform algorithm's third parameter should be an iterator to the start of the range where the values should be written. Specifically, it works by overwriting the values in the range pointed at by the iterator with the transformed values. This means that there actually have to be values there to overwrite in the first place. In your case, you're writing to an empty forward_list, so there's nothing to write to, hence the crash.
To fix this, consider replacing the last argument with a back_inserter, which will automatically create the space that's needed as the values are produced:
std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
std::sregex_iterator(),
back_inserter(results), // <--- This is new
[&](const std::smatch& m)->fs::path{
return root / fs::path(m[1].str());
});
More generally, to the best of my knowledge, all of the algorithms in <algorithm> that write to output ranges will assume that there are values available to overwrite in that range. If that isn't the case, consider using a back_inserter or other type of insert iterator, which will automatically create the space that's needed for you.
Hope this helps!
Your output iterator is a simple results.begin(), which is probably == results.end(). The clue here is that the failure comes when trying to assign the result.
You either need a back_inserter as you found, or to use some container with enough space already allocated (which can only work if you know how many items you're transforming in advance).
Specifically, consider the sample implementation of the first overload here.
The line
*d_first++ = op(*first1++);
requires the destination iterator already to be valid. If it's == end() as suggested, the whole operation is illegal.

std::map::erase infinite loop

I have a map of a vector of char's and a vector of strings. Every so often, if I've seen the vector of characters before, I'd like to add a string to my vector of strings. Below is my code to do that.
map<vector<char>, vector<string>>::iterator myIter = mMyMap.find(vChars);
if(myIter != mMyMap.end()) {
vector<string> vStrings = myIter->second;
mMyMap.erase(myIter);
vStrings.push_back(some_other_string);
mMyMap.insert(pair<vector<char>, vector<string>>(vChars, vStrings));
return TRUE;
}
The call to mMyMap.erase() seems to get stuck an in infinite loop though. I'm guessing it's because vStrings isn't getting a deep-copy of myIter->second.
Do I need to initalize vStrings like:
vector<string> vStrings(myIter->second);
Or what's the proper fix?
I don't see an error in the posted code fragment (other than a missing )). But may I suggest simplifying lines 2-8 to:
if(myIter != mMyMap.end()) {
myIter->second.push_back(some_other_string);
}
vector vStrings = myIter->second;
and
vector vStrings(myIter->second);
are same things. They both call copy constructor. And the copy is deep copy only. My guess is that the vector that is getting copied is too big(or long). Each element of the vector will be copied one by one. And hence the time.

Vector insert() causes program to crash

This is the first part of a function I have that's causing my program to crash:
vector<Student> sortGPA(vector<Student> student) {
vector<Student> sorted;
Student test = student[0];
cout << "here\n";
sorted.insert(student.begin(), student[0]);
cout << "it failed.\n";
...
It crashes right at the sorted part because I can see "here" on the screen but not "it failed." The following error message comes up:
Debug Assertion Failed!
(a long path here...)
Expression: vector emplace iterator outside range
For more information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
I'm not sure what's causing the problem now, since I have a similar line of code elsewhere student.insert(student.begin() + position(temp, student), temp); that does not crash (where position returns an int and temp is another declaration of a struct Student). What can I do to resolve the problem, and how is the first insert different from the second one?
It should be:
sorted.insert(sorted.begin(), student[0]);
You were passing the iterator from the wrong instance.
When you use std::vector::insert ( iterator position, const T& x );, the iterator position must point into that same vector. You're using an iterator from student with sorted.insert, which dies.

C++ Tokenizing using iterators in an eof() cycle

I'm trying to adapt this answer
How do I tokenize a string in C++?
to my current string problem which involves reading from a file till eof.
from this source file:
Fix grammatical or spelling errors
Clarify meaning without changing it
Correct minor mistakes
I want to create a vector with all the tokenized words. Example: vector<string> allTheText[0] should be "Fix"
I don't understad the purpose of istream_iterator<std::string> end; but I included cause it was on the original poster's answer.
So far, I've got this non-working code:
vector<string> allTheText;
stringstream strstr;
istream_iterator<std::string> end;
istream_iterator<std::string> it(strstr);
while (!streamOfText.eof()){
getline (streamOfText, readTextLine);
cout<<readTextLine<<endl;
stringstream strstr(readTextLine);
// how should I initialize the iterators it and end here?
}
Edit:
I changed the code to
vector<string> allTheText;
stringstream strstr;
istream_iterator<std::string> end;
istream_iterator<std::string> it(strstr);
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
vector<string> vec((istream_iterator<string>(streamOfText)), istream_iterator<string>()); // generates RuntimeError
}
And got a RuntimeError, why?
Using a while (!….eof()) loop in C++ is broken because the loop will never be exited when the stream goes into an error state!
Rather, you should test the stream's state directly. Adapted to your code, this could look like this:
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
}
However, you already have a stream. Why put it into a string stream as well? Or do you need to do this line by line for any reason?
You can directly initialize your vector with the input iterators. No need to build a string stream, and no need to use the copy algorithm either because there's an appropriate constructor overload.
vector<string> vec((istream_iterator<string>(cin)), istream_iterator<string>());
Notice the extra parentheses around the first argument which are necessary to disambiguate this from a function declaration.
EDIT A small explanation what this code does:
C++ offers a unified way of specifying ranges. A range is just a collection of typed values, without going into details about how these values are stored. In C++, these ranges are denoted as half-open intervals [a, b[. That means that a range is delimited by two iterators (which are kind of like pointers but more general; pointers are a special kind of iterator). The first iterator, a, points to the first element of the range. The second, b, points behind the last element. Why behind? Because this allows to iterate over the elements very easily:
for (Iterator i = a; i != b; ++i)
cout << *i;
Like pointers, iterators are dereferenced by applying * to them. This returns their value.
Container classes in C++ (e.g. vector, list) have a special constructor which allows easy copying of values from another range into the new container. Consequently, this constructor expects two iterators. For example, the following copies the C-style array into the vector:
int values[3] = { 1, 2, 3 };
vector<int> v(values, values + 3);
Here, values is synonymous with &values[0] which means that it points to the array's first element. values + 3, thanks to pointer arithmetic, is nearly equivalent to &values[3] (but this is invalid C++!) and points to the virtual element behind the array.
Now, my code above does the exact same as in this last example. The only difference is the type of iterator I use. Instead of using a plain pointer, I use a special iterator class that C++ provides. This iterator class wraps an input stream in such a way that ++ advances the input stream and * reads the next element from the stream. The kind of element is specified by the type argument (hence string in this case).
To make this work as a range, we need to specify a beginning and an end. Alas, we don't know the end of the input (this is logical, since the end of the stream may actually move over time as the user enters more input into a console!). Therefore, to create a virtual end iterator, we pass no argument to the constructor of istream_iterator. Conversely, to create a begin iterator, we pass an input stream. This then creates an iterator that points to the current position in the stream (here, cin).
My above code is functionally equivalent to the following:
istream_iterator<string> front(cin);
istream_iterator<string> back;
vector<string> vec;
for (istream_iterator<string> i = front; i != back; ++i)
vec.push_back(*i);
and this, in turn, is equivalent to using the following loop:
string word;
while (cin >> word)
vec.push_back(word);