Unexplained out_of_range in string::substr

c++, g++

Solution

I modified your sample slightly to decrease amount of indentation used. There are 5 "test cases" and none causes any problem. Could you please provide a sample request to reproduce the problem you're having.

EDIT: Forgot to mention: if this sample as it is (with commented-out bits) doesn't produce that error, your best bet is that you have a bug in your `StringExplode` function. You could post its source, to get a more helpful advice.

EDIT2: In your `StringExplode`, change `results[tmpKey] = tmpKey.substr(found+1);` to `results[tmpKey] = tmpResult[i].substr(found+1);`. Change `int found` to `size_t found`, and remove all of `if (found > 0)`, that will fix your mysterious out_of_range. You were `substr`-ing a wrong string. Just in case, here's the code with a fix:

void StringExplode(std::string str, std::string objseparator, std::string keyseperator,
                   std::map <std::string, std::string> &results)
{
    size_t found;
    std::vector<std::string> tmpResult;
    found = str.find_first_of(objseparator);
    while(found != std::string::npos)
    {
        tmpResult.push_back(str.substr(0,found));
        str = str.substr(found+1);
        found = str.find_first_of(objseparator);
    }
    if(str.length() > 0)
    {
        tmpResult.push_back(str);
    }

    for(size_t i = 0; i < tmpResult.size(); i++)
    {
        found = tmpResult[i].find_first_of(keyseperator);
        while(found != std::string::npos)
        {
                std::string tmpKey = tmpResult[i].substr(0, found);
                results[tmpKey] = tmpResult[i].substr(found+1);
                found = tmpResult[i].find_first_of(keyseperator, found + results[tmpKey].size());
        }

    }
}

Initial test code:

#include <iostream>
#include <map>
#include <string>

std::string parse(const std::string &request)
{
    std::map<std::string,std::string> keyval;
    std::string outRequest;

    if(request[0] != 'P')
        return outRequest;

    if(request.find("register") == std::string::npos)
        return outRequest;

    //we have a register request
    size_t bodypos = request.find("username");
    if(bodypos==std::string::npos)
    {
        // HttpError(400,"Malformed HTTP POST request. Could not find key username.",request);
        // you said HttpError returns, so here's a return
        return outRequest;
    }

    std::string body = request.substr(bodypos);
    // StringExplode(body,"&", "=",keyval);
    outRequest = "doing stuff";

    return outRequest;
}

int main()
{

    std::string request("P\r\nregister\r\nusername=hello\r\n\r\n");
    std::cout << "[" << parse(request) << "]\n";

    request = "Pregisternusername=hello\r\n\r\n";
    std::cout << "[" << parse(request) << "]\n";

    request = "Pregisternusername=hello";
    std::cout << "[" << parse(request) << "]\n";

    request = "registernusername=hello";
    std::cout << "[" << parse(request) << "]\n";

    request = "";
    std::cout << "[" << parse(request) << "]\n";

    return 0;
}

This outputs, predictably:

[doing stuff] [doing stuff] [doing stuff] [] []

Problem

I have been getting a really annoying error about an std::out_of_range when calling substr. The exact error is terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr I'm absolutely sure that tmp_request has a length greater then 1. No matter what I pass to substr—1, 2, or bodypos—it always throws that error. I'm using g++ on Unix. Only interesting thing I can include is the string has multiple `"\r\n"`, including one `"\r\n\r\n"`. In one cpp file: ``` std::string tmp_request, outRequest; tmp_request = SS_Twitter->readData(); outRequest = SS_Twitter->parse(tmp_request); ``` In another: ``` std::string parse(const std::string &request) { std::map<std::string,std::string> keyval; std::string outRequest; if(request[0]=='P') { if(request.find("register")!=std::string::npos) { //we have a register request size_t bodypos = request.find("username"); if(bodypos==std::string::npos) { HttpError(400,"Malformed HTTP POST request. Could not find key username.",request); } else { std::string body = request.substr(bodypos); StringExplode(body,"&", "=",keyval); outRequest = "doing stuff"; } } ``` Update: ``` std::string request2("P\r\nregister\r\nusername=hello\r\n\r\n"); std::string body = request2.substr(4); ``` That throws the same error. Now I know this is perfectly valid and correct code, but it's still throwing the error. //removed source link

Original source