-10

I am getting this error when running:

terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr

problem is in this part of code but i brand new and i don't understand how i should solve this problem. content is my vector of strings.

    int i=1;
    std::string v1, v2, weight;
    while(!content.empty())
    {
        v1 = content[i].substr(2,1);
        v2 = content[i].substr(5,1);
        weight = content[i].substr(8,1);
        i++;
    }
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 2
    Hmm, you're accessing the vector out of range. – juanchopanza Apr 10 '14 at 20:59
  • What is the value of `content[i]` when the error happens? – Barmar Apr 10 '14 at 21:05
  • 1
    @juanchopanza The error is in `substr`, not the vector accessor. – Barmar Apr 10 '14 at 21:05
  • The error indicates that your arguments to `substr` are too high for the length of the string you're accessing. So one of the strings must be less than 9 characters long. – Barmar Apr 10 '14 at 21:07
  • @Barmar That is also possible. But we can't know that from the code shown. The put of bounds access of the vector is completely clear. – juanchopanza Apr 10 '14 at 21:08
  • @Barmar: He's also accessing the vector out of range anyway since his loop termination condition is broken. The code has _multiple_ problems. – Lightness Races in Orbit Apr 10 '14 at 21:08
  • That's very true. When he fixes the substr problem, he'll get the new error for the vector. – Barmar Apr 10 '14 at 21:09
  • 1
    @Barmar How can you be so sure there's a problem with `substr`? Have you seen the strings stored in the vector? – juanchopanza Apr 10 '14 at 21:10
  • The error message clearly says that the error happened in `basic_string::substr`. – Barmar Apr 10 '14 at 21:12
  • @Barmar Ah yes, that constitutes undeniable evidence. – juanchopanza Apr 10 '14 at 21:12
  • in vector i have string e.g (v1-v2)=8 when v1 and v2 is verticles and 8 is weight. – user3084640 Apr 10 '14 at 21:13
  • Which line is the error happening on? Are you sure that the string is correct for that value of `i`? Have you used a debugger to try to examine the values of all the variables when the error happens? – Barmar Apr 10 '14 at 21:15
  • @juanchopanza: Well, no; he's invoking UB with these vector accesses, so technically the exception could say anything regardless of where it was thrown from :P – Lightness Races in Orbit Apr 10 '14 at 21:15
  • @LightnessRacesinOrbit Doesn't `std::vector` also signal `out_of_range`? – Barmar Apr 10 '14 at 21:17
  • @LightnessRacesinOrbit Not if the `substr` error comes before the vector out of range problem, no? – juanchopanza Apr 10 '14 at 21:17
  • @juanchopanza: No, I mean, we can't rule out the possibility that there _isn't_ a `substr` error, but the UB has caused a random exception to be thrown with misleading text. – Lightness Races in Orbit Apr 10 '14 at 21:19
  • 1
    @Barmar: Not when you do `[]` on it, no. – Lightness Races in Orbit Apr 10 '14 at 21:20
  • @Barman i think in last line because results of loop is good. QT Creator don't show any problem, compile it, only console show error after print loop. – user3084640 Apr 10 '14 at 21:22
  • 1
    You think or you know? Doesn't the debugger tell you exactly what line the error happened on? How can the result of the loop be good, since the loop never ends? The `while` condition will never become true, because you're not removing anything from `contents` during the loop. – Barmar Apr 10 '14 at 21:26
  • thanks for help, i change '!content.empty()' for 'sizeof(content)' and work! :) – user3084640 Apr 10 '14 at 21:32
  • 6
    @user3084640: Um, that's wrong too. It's actually a lot _more_ wrong. Why are you trying to control your loop's lifetime based on whether the vector is empty, when the vector is never reduced in size during the loop? New to C++ or not that just lacks common sense. Look at the section in your C++ book about how to iterate over containers. – Lightness Races in Orbit Apr 10 '14 at 21:35

2 Answers2

3

Two main problems here.

Your loop will go on forever (or until you murder your RAM sticks from invalid accesses), because you only check that the vector is not empty, rather than checking that i has reached its total size.

for (auto& x : content) {
    const std::string v1     = x.substr(2,1);
    const std::string v2     = x.substr(5,1);
    const std::string weight = x.substr(8,1);

    // Presumably actually do something with these now
}

Then you need to fix your substr operations, which have the wrong arguments and are thus causing the exception.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

Let's try to fix your program snippet:

int i=1;
std::string v1, v2, weight;
while( i < content.size() && content[i].size() >= 8 )
{
    v1 = content[i].substr(2,1);
    v2 = content[i].substr(5,1);
    weight = content[i].substr(8,1);
    i++;
}

That was the minimal fix. I would have preferred:

std::string v1, v2, weight;
content.erase(content.begin());
for( const auto& x: content )
{
    if( x.size() < 8 )
         continue; // or break, whatever is best

    v1 = x.substr(2,1);
    v2 = x.substr(5,1);
    weight = x.substr(8,1);
}

You can also vary how you'll treat the shorter items:

inline int guarded_substr(const std::string& s, std::size_t begin, size_t size) {
    return s.size() >= begin+size ? s.substr(begin, size) : std::string();
}

std::string v1, v2, weight;
content.erase(content.begin());
for( const auto& x: content )
{
    v1 = guarded_substr(x,2,1);
    v2 = guarded_substr(x,5,1);
    weight = guarded_substr(x,8,1);
}

And so on...

Massa
  • 8,647
  • 2
  • 25
  • 26