2

I have two classes, each has a vector of pointers to Data. What I want to do is to assign pointers in the vector of the class Sample2 to pointers in the vector of the class Sample1. The problem is that as I assign pointers in the second vector, the order in witch they are stored is that of the first vector. I would like to store them in the order of insertion.

Here is a minimal reproducible example of the code:

#include <iostream>
#include <vector>

using namespace std; //for sample purposes

// For simplicity, the data is just a string in this example.
using Data = string;
// In the real code there is a class with a certain vector as a member,
// but for this example we can reduce it to just the vector.
using Sample1 = vector<Data*>;

Class Sample2 — the problem is here

class Sample2 {
    vector<Data*> autodromos2;

public:
    vector<Data*>& getAutodromos() { return autodromos2; }

    // ** This is the function with the problem. **
    void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
    {
        for (Data* a : autodromos) {
            for (string &s : arguments) {
                if (s == *a) { // The real test is more complex.
                    getAutodromos().push_back(a);
                    break;
                }
            }
        }
    }
};

Main function (generate data and call addAutodromos2)

int main()
{
    // Create the list of elements to add to a `Sample2`.
    // Note that these are strings, not Data objects (in the real code).
    vector<string> arguments { "fourth", "first", "third" };

    // Create the `Sample1` data with which to work.
    Sample1 s1 {
        new Data("first"), new Data("second"), new Data("third"), 
        new Data("fourth"), new Data("fifth") 
    };

    // Create the `Sample2` data from the list and `s1`.
    Sample2 s2;
    s2.addAutodromos2(arguments, s1);

    // Diagnostic:
    for (Data* a : s2.getAutodromos()) {
        cout << *a << endl;
    }
}

The output is

first 
third 
fourth

when it should be

fourth 
first 
third
0

2 Answers 2

3

Actually the sequence problem with loops in addAutodromos2() you need to change function with below code:

    for (string s : arguments) 
    {
        for (Data* a : autodromos) 
        {            
            if (s == *a) { // The real test is more complex.
                getAutodromos().push_back(a);
                break;
            }
        }
    }

Switch the for-loops. output is fourth first third

Hope this will help.

Sign up to request clarification or add additional context in comments.

Comments

1

There is a school of thought that says if you have nested loops inside a function, you probably are not thinking abstractly enough. While that might be an overstatement at times, it does have value in this situation. Let's look at the inner loop.

            for (string s : arguments) {
                if (s == *a) {
                    getAutodromos().push_back(a);
                    break;
                }
            }

This loop searches for *a in arguments and if found does something. The search is a concept that could be abstracted away into its own function, let's call it found, a function that returns a bool.

    // Preliminary revision
    void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
    {
        for (Data* a : autodromos) {
            if ( found(arguments, *a) ) {
                getAutodromos().push_back(a);
            }
        }
    }

With only one loop to look at, it should be clearer what the problem is. Elements are added to getAutodromos() in the order they appear in autodromos. To use the order within arguments, you need to loop through it. (I'll change the name of the helper function to find_by_name and have it return either an iterator to the found element or the end iterator. A boolean return value is no longer adequate.)

    // Final revision
    void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
    {
        for (string s : arguments) {
            auto result = find_by_name(autodromos, s);
            if ( result != autodromos.end() ) {
                getAutodromos().push_back(*result);
            }
        }
    }

A missing piece here is the find_by_name function. The good news is that this task is so common, that functionality is part of the standard library, in the header <algorithm>. The bad news is that there is a bit of typing to use the library function, as the arguments are more complex (for greater flexibility). You may want to define a wrapper to specialize it to your case.

// Returns an iterator to the element with the indicated name, or
// autodromos.end() if not found.
static auto find_by_name(const vector<Data*> & autodromos, const string & name)
{
    return std::find_if(autodromos.begin(), autodromos.end(), [&name](Data *a){
        return name == *a; // or name == a->get_name(), when Data is more complex
    });
}

Note that if the real test was as simple as comparing name == *a, then std::find could be used instead of std::find_if, and there would be no need to use a lambda. Don't forget to #include <algorithm> earlier in the file.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.