Please consider this C++ question:

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

class ParseURL{
        int qualify; // 0 means we qualify
        string node;
        string service;
        bool primary;
        bool health;
        string epoch;
        // methods
        ParseURL(string URL);

ParseURL::ParseURL(string URL){
    vector<string> g2 = {"node", "service", "primary", "health", "epoch"};

    for (string tag : g2){
        auto found = URL.find(tag);
        if ( found != string::npos ){
            auto cut_from = found + 1 + tag.size() ;
            auto meh = URL.substr(cut_from, URL.substr(cut_from).find("&") );
            // is there a way we can avoid these lines below?
            if (tag.find("node",0) == 0){
                this->node = meh;
            } else if (tag.find("service",0) == 0 ){
                this->service = meh;
            } else if (tag.find("epoch",0) == 0) {
                this->epoch = meh;
            } else if (tag.find("health",0) == 0){
                this->health = (meh == "OK");
            } else if (tag.find("primary",0) == 0 ){
                this->primary == (this->node == meh);


    cout << "Tearing Down the class\n";
int main(){
    char req[] = "GET /register?node=hostrpi3&service=potatoservice&primary=node1&health=OK&epoch=1559345106 HTTP";
    string Request = req;
    Request = Request.substr(Request.find_first_of(" ") );
    Request = Request.substr(0, Request.find(" HTTP"));
    ParseURL *a = new ParseURL(Request);

    cout << "a->node: " << a->node << endl;
    cout << "a->service: " << a->service << endl;
    cout << "a->epoch: " << a->epoch << endl;
    cout << "a->health: " << a->health << endl;
    cout << "a->primary: " << a->primary << endl;


    return 0;

I need to represent a object based on URL Query Strings, the tags I need are represented in vector g2, and as you can see, I make datamembers for ParseURL out of those tags.

The o/p looks like:

   a->node: hostrpi3
a->service: potatoservice
  a->epoch: 1559345106
 a->health: 1
a->primary: 0
Tearing Down the class

Although this version works, it feels this can be improved much. Despite having it all in the Vector, I am repeatedly doing tag.find for each of those attributes. There must be a better way, I hope. Could you please point in the right direction? Thanks!

Edit 1

Thanks, I updated the constructor following the suggestions:

ParseURL::ParseURL(string URL){
    char tags[10][100] = {"node", "service", "primary", "health", "epoch"};

    int i = 0;
    for (auto tag : tags){
        auto found = URL.find(tag);
        if ( found != string::npos ){
            auto cut_from = found + 1 + strlen(tag);
            auto tag_info = URL.substr(cut_from, URL.substr(cut_from).find("&") );
            switch (i){
                case 0:
                    this->node = tag_info; 
                case 1:
                    this->service = tag_info; 
                case 2:
                    this->primary = (this->node == tag_info); 
                case 3:
                    this->health = (tag_info == "OK"); 
                case 4:
                    this->epoch = tag_info; 

bash for example, offers indirect reference of variables - that is, one variable may contain the name of another variable:

$ cat 

values="value1 value2"
value1="this is value1"
value2="this is value2"

for i in $values; do 
    echo "$i has value ${!i}"

$ ./ 
value1 has value this is value1
value2 has value this is value2

I was hoping something similar exists for cases like this, nevertheless, I learned valuable lessons here. thank you!

2 Answers

Mr.WorshipMe On

I didn't exactly understand what you want to use that indirection for in you example, but here's how it can be done:

vector<string> values{"value1", "value2"}
map<const string, const string> fields_and_values{{"value1", "this is value1"}, {"value2", "this is value2"}};
for (value: values)
     cout << value << " have value " << fields_and_values[value] << endl;

This code allows you to dynamically add more fields. If you have a predefined number of fields, this is an overkill, and a simple array would do. i.e.

array<const string, 2> values{"this is value1", "this is value2"};
for (int i = 0; i < 2; ++i)
    cout << "value" << i << " have value " << values[i] << endl;

Hope that answers your question.

In general about your code:

Why did you go from vector<string> to char[10][100]? (esp. when you only have 5 strings, and none of them take up 100 chars?) array<string, 5> is the way to go for your case.

Also, don't use new and delete.. There's no reason to do a heap allocation, just use ParseURL parse(request) (and even if there was a good reason - use unique_ptr instead).

And finally, if you don't want to go over the string multiple times looking for different keywords, you could use regex.

Davis Herring On

Assuming that you want to keep the distinct class members (rather than one key-value store), you can use a static table of strings and pointers to members:

vector<pair<string,string ParseURL::*>> keys={{"node",&ParseURL::node},…};

But that doesn’t work here because the types are different and because the processing isn’t identical for each. Instead, for this sort of almost-parallelism, the syntactically optimal choice is often a lambda:

const auto get=[&URL](const string &tag) {
  auto found = URL.find(tag);
  if(found == string::npos) return "";
  auto cut_from = found + 1 + tag.size() ;
  return URL.substr(cut_from, URL.substr(cut_from).find("&") );

This style has the advantage of definitely initializing health and primary. With sufficient contortions with a private constructor, it can be put into a member initializer list, which is even better practice.