C++ 字符串::substr中的\u超出\u范围,原因不明

C++ 字符串::substr中的\u超出\u范围,原因不明,c++,g++,C++,G++,我在调用substr时遇到了一个非常恼人的错误,关于std::out_of_range。确切的错误是 在抛出一个 “std::超出范围”的实例 what():基本字符串::substr 我绝对肯定tmp_请求的长度大于1。无论我传递给substr-1、2或bodypos的是什么,它总是抛出那个错误。我正在Unix上使用g++ 我能包括的唯一有趣的事情是字符串有多个“\r\n”,包括一个“\r\n\r\n” 在一个cpp文件中: std::string tmp_request, outReques

我在调用substr时遇到了一个非常恼人的错误,关于std::out_of_range。确切的错误是

在抛出一个 “std::超出范围”的实例
what():基本字符串::substr

我绝对肯定tmp_请求的长度大于1。无论我传递给substr-1、2或bodypos的是什么,它总是抛出那个错误。我正在Unix上使用g++

我能包括的唯一有趣的事情是字符串有多个
“\r\n”
,包括一个
“\r\n\r\n”

在一个cpp文件中:

std::string tmp_request, outRequest;

tmp_request = SS_Twitter->readData();
outRequest = SS_Twitter->parse(tmp_request);
另一方面:

 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";
    }

   }
这会抛出同样的错误。现在我知道这是完全有效和正确的代码,但它仍然抛出错误。
//删除源链接后,您似乎需要一个else

if(bodypos==std::string::npos)
{
    HttpError(...);
}

否则您将调用ByDys= nPoS

< P>子字符串,您可以考虑使用(无符号)类型<代码> STD::String::siZeHype类型< /C> >而不是<代码> int < /C> > < /P> 为什么在此处将find的结果转换为int:

int(request.find(“register”)=std::string::npos

您确定它在
substr
上失败,而不是在
HttpError
StringExplode
函数中的
substr
调用上失败吗?如果您还没有,那么应该通过调试器运行它,这样您就可以确切地看到它抛出异常的位置。或者,您可以添加:

std::cout << "calling substr" << std::endl;

如果
substr
确实引发了异常,那么您就知道了,因为程序将打印“calling substr”,而没有匹配的“finished calling substr”。但是,如果它打印了一对调试消息,或者根本没有,那么其他东西会引发异常。

我稍微修改了您的示例以减少缩进量。
有5个“测试用例”,没有一个会导致任何问题。请您提供一个示例请求,以重现您遇到的问题

编辑:忘了提及:如果这个示例(带有注释掉的位)没有产生该错误,那么您最好的选择是您的
StringExplode
函数中有一个bug。您可以发布其来源,以获得更有用的建议

编辑2: 在
StringExplode
中,更改
results[tmpKey]=tmpKey.substr(find+1)
结果[tmpKey]=tmpResult[i].substr(找到+1)。将
int found
更改为
size\u t found
,并删除所有
if(found>0)
,这将修复您神秘的超出范围。您正在
substr
-ing一个错误的字符串。以防万一,下面是带有修复程序的代码:

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());
        }

    }
}
void StringExplode(std::string str、std::string objsepator、std::string keyseperator、,
标准::地图和结果)
{
未找到尺寸;
std::向量tmpreslt;
found=str.find_first_of(objseparator);
while(找到!=std::string::npos)
{
tmpResult.push_back(str.substr(0,找到));
str=str.substr(发现+1);
found=str.find_first_of(objseparator);
}
如果(str.length()>0)
{
t压力后推(str);
}
对于(size_t i=0;i
初始测试代码:

#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;
}
#包括
#包括
#包括
字符串解析(常量std::字符串和请求)
{
std::map-keyval;
std::字符串输出请求;
如果(请求[0]!=“P”)
返回请求;
if(request.find(“register”)==std::string::npos)
返回请求;
//我们有一个注册请求
size_t bodypos=请求.查找(“用户名”);
if(bodypos==std::string::npos)
{
//HttpError(400,“格式错误的HTTP POST请求。找不到密钥用户名。”,请求);
//你说HttpError返回,所以这里有一个返回
返回请求;
}

std::string body=request.substr(bodypos); //StringExplode(主体“&”、“=”、keyval); outRequest=“做事”; 返回请求; } int main() { 字符串请求(“P\r\nregister\r\nusername=hello\r\n\r\n”);
std::cout您的代码有一个相当明显的错误:

int k = read(ns, buf, sizeof(buf)-1);
buf[k] = '\0';
您没有检查read()是否成功,它在失败时返回-1,如果失败,将导致各种内存损坏问题

此外:


您应该再次测试写入是否成功,以及写入的字节是否与您请求的字节数相同,尽管这不会直接导致substr()错误。

std::string body=request.substr(bodypos);。现在回到我的问题:)好的,我已经从回答中删除了该问题(“异常发生在哪里?”)那么我的第二个问题呢:为什么要强制转换为int?find返回一个未签名的std::string::size_type Hi Stanislav。自从我发布了这个答案后,您已经编辑了原始问题,所以强制转换现在消失了,您使用size_t(不是std::string::size_type,但您明白了)。你能确认你也编辑并测试了你的代码,并且异常仍然发生吗?干杯。是的,它仍然发生。我甚至硬编码了一个测试字符串并调用了substr,它给出了相同的错误。不,因为HttpError退出了程序。我感谢你的建议,但我在这里发布的主要原因是为了找出substr失败的原因“在好的字符串上设置断点。@Stanislav Palanik:永远找不到错误的方法是对错误有一个预先的概念。创建一个包含此代码的小测试程序,然后调用它。在调试器中设置一个断点,当你在代码中一步一步地检查变量时,你会看到你的错误。作为记录,这个答案是poste。”在
else
存在之前,以及(显然)在我们知道
HttpError
将退出t之前
#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;
}
int k = read(ns, buf, sizeof(buf)-1);
buf[k] = '\0';
char * buf2 = const_cast<char *>(reply.c_str());
write(ns,buf2,sizeof(buf2));
write(ns, buf2, reply.size() );