C++ vector 、const char *、变量作用域和生命周期

标签 c++ variables pointers vector

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

我这里有几个问题:

  • 解析似乎正确进行,但我存储/传递提取变量内容的方式无法正常工作,这可能是由于误解了变量的存储/检索方式及其在 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

最佳答案

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

这部分是未定义的行为。

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

关于C++ vector 、const char *、变量作用域和生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36230848/

相关文章:

math - ARM 汇编浮点变量

python - 如何从修改后的字符串列表创建 gtk.STOCK_* 按钮?

python - 使用函数更改参数值?

c++ - 在这个失败的 C++ 类实例化中,我忽略了什么明显的事情?

c++ 字符串和指针混淆

c++ - 静态成员初始化链接错误

c++ - 使用/clr 或 clr :pure (cpprestsdk aka casablanca) 编译时不支持互斥锁

c++ - SFINAE : What is happening here?

c - c 中的指针- "is a pointer; did you mean to use ' ->'?"

c++ - Qt - 图像类 - 非最大抑制 - C++