2016-03-26 19 views
1

Bu kod parçasının istekleri ayrıştırması, URI yolunu ayıklaması, ardından her bir üstbilgiyi ve onun değerini ayıklaması ve ardından tüm bu ayıklanan değişkenleri son olarak iletilecek olan std::vector <const char*> cva içine iletmesi gerekir.C++ vektörler, const char *, değişkenler kapsamı ve kullanım ömrü

std::vector<std::vector<const char*>> nv (config.nv.push_back(std::move(cva));) için burada birkaç sorun vardır:

  • ayrıştırma doğru oluyor ama yolu ben çıkarılan değişkenin içeriğini geçirerek/depolamak.Bu bir yanlış anlaşılma yüzünden ya düzgün çalışmıyor gibi görünüyor değişkenlerin nasıl saklandığını/retr C++ (ve büyük olasılıkla C++ öğrenmeye başladığımdan beri) ya da farkında olmadığım bazı daha büyük bir konu olan ben ve onların kapsamı.
  • Ayrıştırma işlemimin doğru yapıldığını gösteren bazı print ifadelerini ekledim. Ancak, for döngülerinin (sonunda) farklı çıktısı bekleniyor.

i

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

beklenen çıktı olmalıdır:

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 

gerçek çıktı:

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 

cevap

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

Bu bölüm tanımlanmamış bir davranıştır.

cva, yerel işaretçilerle const char * bir vektördür. Geçici bir nesnenin c_str(), burada çağırıyorsunuz. Bu geçici std::string nesnesi hemen kapsam dışıdır ve ifadenin sonunda const char * iç içeriğinin geçerli olmadığı noktada yok olur. Bu işaretçi, yok edilen bir nesnenin iç içeriğine cva vektörüne eklenir ve daha sonra yazdırılmaya çalışılır, dolayısıyla tanımlanmamış davranış.

+0

Açıklama için teşekkürler. Const char * ''in cuma boşluğunun başka bir dış kütüphane tarafından kullanıldığını ve değiştiremediğini biliyorum. Bu tanımlanmamış davranışı atlamak için en iyi yaklaşım nedir. yani (tok.substr (0, pos)) içeriğini kopyalamalıyım. c_str() 've' (tok.substr (pos + 1, std :: string :: npos)). c_str() 'diğerlerine değişkenleri ve sonra bu değişkenleri 'cva.push_back()' ye iletin. veya bu kullanım durumunu ele almak için daha iyi, daha zarif bir yol var mı? –

+0

Evet, gerçek dizeyi ayrı bir vektöre kopyalamanız gerekiyor ve ** tüm dizeler kopyalandıktan sonra, "const char *" için ayrı bir vektör oluşturun. –

+0

Bu işe yaradı! Teşekkürler. C++ 'yı öğrendiğimden beri, çözdüğüm çözümü yayınladığımda sorun olur mu? Bu konuda bazı geri bildirimler alabilir ve en iyi uygulamalar nelerdir? Kodu daha zarif ve daha verimli hale getirecek bazı şeyler var ve C++ uzmanlarından bu tür geri bildirimler almak istiyorum! –