Search code examples
c++vectoriteratorclone

Cloning a vector of pointers, can I clone an iterator somehow too?


Have a look at my code:

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

class AbstractBase
{
protected:
    int ident;
public:
    virtual void add() = 0;   
    int getIdent()const {return ident;}
    virtual ~AbstractBase(){};
    virtual AbstractBase* clone()const =0;
};

class Derived1 :public AbstractBase
{    
public:
    Derived1(int i)
    {
        ident=i;
    };
    virtual void add() override
    {
        ident+=1;
    }
    virtual AbstractBase* clone() const override
    {
        return new Derived1 (*this);
    }
};

class Derived2 :public AbstractBase
{    
public:
    Derived2(int i)
    {
        ident=i;
    }
    virtual void add() override
    {
        ident+=2;
    }
    virtual AbstractBase* clone() const override
    {
        return new Derived2(*this);
    }
};

class cloneFunctor
{
public:
    AbstractBase* operator() (AbstractBase* a) const
    {
        return a->clone();
    }
};

struct IdentCompare
{
    bool operator()(AbstractBase* f)
    {
        return f->getIdent() >5;
    }
};

void WorkWithClonedVector(vector<AbstractBase*>origList,vector<AbstractBase*>::iterator it)
{
    vector<AbstractBase*> tempList;
    transform(origList.begin(),origList.end(),back_inserter(tempList),cloneFunctor());
    //NEED TO FIND ITERATOR AGAIN-->ANY OTHER OPTION?
    vector<AbstractBase*>::iterator tempIt=find_if(tempList.begin(),tempList.end(),IdentCompare());
    (*tempIt)->add();
    cout<<"local list:\n";
    for(unsigned int i=0;i<tempList.size();++i)
    {
        cout<<"Element "<<(i+1)<<": "<<tempList[i]->getIdent()<<'\n';
        delete tempList[i];
    }
    cout<<"Original Iterator still pointing to: "<<(*it)->getIdent()<<'\n';
    tempList.clear();
}


int main()
{
    Derived1 d1(1);
    Derived1 d1b(2);
    Derived2 d2(7);
    Derived2 d2b(5);
    vector<AbstractBase*> List;
    List.push_back(&d1);
    List.push_back(&d1b);
    List.push_back(&d2);
    List.push_back(&d2b);
    vector<AbstractBase*>::iterator iter = find_if(List.begin(),List.end(),IdentCompare());
    WorkWithClonedVector(List,iter);
    cout<<"Original List not changed:\n";
    for(unsigned int i=0;i<List.size();++i)
    {
        cout<<"Element "<<(i+1)<<": "<<List[i]->getIdent()<<'\n';
    }
}

As you can see I successfully managed to clone a vector<AbstractBase*> within WorkWithClonedVector in order to safely work on the temporary list without changing anything in the original List. I was wondering if there is any possibility to "clone" the iterator in the parameter list of WorkWithClonedVector too, so I don't need to use find_if twice? To summarize it: if the iterator in the parameter list is pointing to the third element of the original list, I'd also like the cloned iterator to point to the third element of the cloned list.


Solution

  • In your code, you may use instead:

    auto tempIt = std::next(tempList.begin(), std::distance(origList.begin(), it));
    

    or, as you work with std::vector

    auto tempIt = tempList.begin() + (it - origList.begin());
    

    Demo

    Note that you have to pass origList by (const)reference, else std::distance(origList.begin(), it)); would be UB as the iterator won't belong to the same range.