Этот фрагмент кода должен анализировать запросы, извлекать путь URI, затем извлекать каждый отдельный заголовок и его значение, а затем передавать все эти извлеченные переменные в std::vector <const char*> cva
, которые в конечном итоге будут переданы в std::vector<std::vector<const char*>> nv (config.nv.push_back(std::move(cva));)
C++ векторы, const char *, scope scope и lifetime
у меня есть несколько проблем здесь:
- кажется, что синтаксический анализ правильно происходит, но, как я храню/передавая содержание извлеченной переменной не работает должным образом или из-за неправильного понимания как хранятся переменные ieved и их область действия в 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 vactor 'const char *' используется другой внешней библиотекой, и я не могу ее изменить. Каков наилучший подход к обходу этого неопределенного поведения. то есть я должен скопировать содержимое '(tok.substr (0, pos)). c_str()' и '(tok.substr (pos + 1, std :: string :: npos)). c_str()' в другой переменные, а затем передать эти переменные в 'cva.push_back()'. или есть лучший, более элегантный способ справиться с этим вариантом использования? –
Да, вам нужно скопировать фактическую строку в отдельный вектор, и ** после ** все строки скопированы, постройте отдельный вектор 'const char *'. –
Это сработало! Благодарю. Поскольку я изучаю C++, это нормально, если я опубликую решение, которое я выяснил, чтобы получить некоторые отзывы об этом и какие лучшие практики? Есть, конечно, некоторые вещи, которые сделают код более элегантным и более эффективным, и я хотел бы получить такую обратную связь от экспертов C++! –