C ++向量,const char *,变量范围和生命周期

时间:2016-03-26 02:09:37

标签: c++ variables pointers vector

这段代码应该解析请求,提取URI路径,然后提取每个单独的头及其值,然后将所有提取的变量传递给std::vector <const char*> cva,最终将传递给std::vector<std::vector<const char*>> nv (config.nv.push_back(std::move(cva));) < / p>

我在这里遇到的问题很少:

  • 似乎解析正确发生但是我存储/传递提取变量内容的方式由于误解了变量的存储/检索方式以及它们在C ++中的范围而无法正常工作(很可能是因为我几乎没有开始学习C ++)或一些我不知道的更大的问题。
  • 我插入了一些print语句,表明我的解析已经正确完成。
  • 但是for循环(在结尾处)具有与预期不同的输出。


#include <vector>
#include <cstring>
#include <iostream>  
#include <string> 

namespace {
std::vector<std::string> explode(const std::string& str, const char& ch) {
std::string next;
std::vector<std::string> result;

// For each character in the string
for (std::string::const_iterator it = str.begin(); it != str.end(); it++) {
    // If we've hit the terminal character
    if (*it == ch) {
        // If we have some characters accumulated
        if (!next.empty()) {
            // Add them to the result vector
            result.push_back(next);
            next.clear();
        }
    } else {
        // Accumulate the next character into the sequence
        next += *it;
    }
}
if (!next.empty())
     result.push_back(next);
return result;
}
}

int main() {
// this is an example of how my reqlines looks like
   std::vector<std::string> reqlines;
   reqlines.push_back("https://endpoint/test1");
   reqlines.push_back("https://endpoint/test2\theader1:1234\tcookie:abcd");
   reqlines.push_back("https://endpoint/test3\theader1:5678");
   reqlines.push_back("https://endpoint/test4");
   reqlines.push_back("https://endpoint/test5");

   std::vector<std::string> paths;
   std::vector<std::string> extraheaders;
   std::vector<std::vector<std::string> > tokenized;
   int count = 0;   // keeps track of each request number so I can access its corresponding extra headers from extraheaders vector
   bool cond = true;

   if (cond){
    // creating which will be used to store my requests paths as well as extra headers
    // This has to be a const char * vector since it will be used by an external library which requires such type
    std::vector<const char *> cva;

    for (auto &req : reqlines){
            unsigned int pos = req.find_first_of("\t", 0);
            if (pos == -1){
                    paths.push_back(req);
                    extraheaders.push_back(" ");
            } else {
                    paths.push_back(req.substr(0, pos));
                    extraheaders.push_back(req.substr(pos+1, std::string::npos));
            }
    }

    for (auto &path : paths){
            cva.push_back(":path");
            cva.push_back(path.c_str()); // adding the URI path into cva variable  

            // explode function which returns a std::vector<std::string> when passing an std::string to it
            tokenized.push_back(explode(extraheaders[count], '\t'));  // extracting the vector<std::string> of all extra headers

    //      if (tokenized[count][0].compare(" ") == 0){
    //              printf("   %d   element is empty is skipped  \n");
    //      }else { 

            for (auto &tok : tokenized[count]){   // looping through extra headers of request number "count", parsing header name/value and adding it to cva
                printf(" %d   tok  %s\n", __LINE__, tok.c_str());
                printf(" %d   tok address    %d\n", __LINE__, &tok);
                unsigned int pos = tok.find_first_of(":", 0);
                if (pos == -1 )
                    printf("  %d  there are no headers \n", __LINE__);
                else {
                    printf("header name:   %s\n", (tok.substr(0, pos)).c_str());
                    printf("header value:   %s\n", (tok.substr(pos+1, std::string::npos)).c_str());
                    cva.push_back((tok.substr(0, pos)).c_str());
                    cva.push_back((tok.substr(pos+1, std::string::npos)).c_str());
                }
            }
            cva.push_back(":version");  // adding version header
            cva.push_back("HTTP/1.1");  // adding version header number
            cva.push_back(nullptr);  // adding nullptr (which is how nv is expecting cva to be terminated)
            count++;

            // passing the cva content to nv 
            //config.nv.push_back(std::move(cva));
    }

    // Below are the printing statement to check the values of the different variables I created and populated 
    // above, my problem is that the population process puts some values into my variables however printing
    // the content of the those variables shows different values from what I am expecting

            std::cout << "          " << std::endl << std::endl;
            std::cout << "Printing cva" << std::endl;
            for (auto &elem : cva){
                    if (elem == nullptr)
                            std::cout << static_cast<void*>(nullptr) << std::endl;
                    else
                            std::cout << &elem << "   " <<elem << std::endl;
            }
            std::cout << "          " << std::endl << std::endl;
            std::cout << "Printing paths" << std::endl;
            for (auto &path : paths){
                    std::cout << &path << "    " << path << std::endl;
            }
            std::cout << "          " << std::endl << std::endl;
            std::cout << "Printing headers" << std::endl;
            for (auto &hed : extraheaders) {
                    std::cout << &hed << "    "<<hed << std::endl;
            }
    }
}

预期输出应为:

Printing cva
:path
endpoint:port/test1
:version
HTTP/1.1
0
:path
endpoint:port/test2
:header1
1234
:cookie
abcd
:version
HTTP/1.1
0
:path
endpoint:port/test3
:header1
5678
:version
HTTP/1.1
0
:path
endpoint:port/test4
:version
HTTP/1.1
0
:path
endpoint:port/test5
:version
HTTP/1.1
0

实际输出:

 Printing cva
   :path
   endpoint:port/test1
   :version
   HTTP/1.1
   0
   :path
   endpoint:port/test2
   header1  // for test2 request, header1 value is 1234
   5678
   header1  // header 1 should not be printed twice
   5678
            // Missing cookie header and value
   :version
   HTTP/1.1
   0
   :path
   endpoint:port/test3
   header1
   5678
   :version
   HTTP/1.1
   0
   :path
   endpoint:port/test4
   :version
   HTTP/1.1
   0
   :path
   endpoint:port/test5
   :version
   HTTP/1.1
   0

1 个答案:

答案 0 :(得分:2)

                cva.push_back((tok.substr(0, pos)).c_str());
                cva.push_back((tok.substr(pos+1, std::string::npos)).c_str());

这部分是未定义的行为。

cvaconst char *本地指针的向量。您在此处调用临时对象c_str()。此临时std::string对象立即超出范围,并在表达式结束时被销毁,此时const char *的内部内容不再有效。这个指向被破坏对象内部内容的指针被添加到cva向量中,稍后会尝试打印它,因此会出现未定义的行为。