Search code examples
c++vectorerase

remove index from vector of type <T> before concatenating two vectors with operator+


my function takes in 2 vectors, compares the elements in each vector for duplicates. If duplicate is found, I want to erase that element from the second vector.

I get a compiler error when I call the erase method. I believe it's because Vector<T> is not the same type as vector<int>::iterator but I am not sure how to fix this.

Could someone suggest how would I fix this?

template <typename T>
std::vector<T> operator+(const std::vector<T>& v1, const std::vector<T>& v2)
{
    typename std::vector<T> newVectorOne = v1;
    typename std::vector<T> newVectorTwo = v2;
    for (std::vector<int>::const_iterator i = newVectorOne.begin(); i != newVectorOne.end(); i++)
    {
        for (std::vector<int>::const_iterator j = newVectorTwo.begin(); j != newVectorTwo.end(); j++)
        {
            if (*i == *j)
            {
                newVectorTwo.erase(newVectorTwo.begin() + j); //error here
            }
        }
    }
    newVectorOne += NewVectorTwo;
    return newVectorOne;
}

error log:

1>------ Build started: Project: Assignment2, Configuration: Debug Win32 ------
1>main.cpp
1>c:\users\rm\documents\comp3512_2\assignments\assignment2\assignment2.h(67): error C2678: binary '+': no operator found which takes a left-hand operand of type 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>' (or there is no acceptable conversion)
1>        with
1>        [
1>            _Ty=int
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.11.25503\include\vector(332): note: could be 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>> std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>::operator +(int) const'
1>        with
1>        [
1>            _Ty=int
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.11.25503\include\vector(361): note: or       'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>> std::operator +<std::_Vector_val<std::_Simple_types<_Ty>>>(int,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>)'
1>        with
1>        [
1>            _Ty=int
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.11.25503\include\vector(243): note: or       'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<_Ty>>> std::operator +<std::_Vector_val<std::_Simple_types<_Ty>>>(int,std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>)'
1>        with
1>        [
1>            _Ty=int
1>        ]
1>c:\users\rm\documents\comp3512_2\assignments\assignment2\assignment2.h(67): note: while trying to match the argument list '(std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>, std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>)'
1>        with
1>        [
1>            _Ty=int
1>        ]
1>c:\users\rm\documents\comp3512_2\assignments\assignment2\main.cpp(36): note: see reference to function template instantiation 'std::vector<int,std::allocator<_Ty>> operator +<int>(const std::vector<_Ty,std::allocator<_Ty>> &,const std::vector<_Ty,std::allocator<_Ty>> &)' being compiled
1>        with
1>        [
1>            _Ty=int
1>        ]
1>Done building project "Assignment2.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Solution

  • The problem is that you are adding two iterators together at this line:

    newVectorTwo.erase(newVectorTwo.begin() + j); //error here
    

    Such an operation doesn't exist: you only want one iterator which you increment and dereference, or an incrementing integral offset that you turn into an iterator when deletion is needed. Taking the latter solution as a template, you could change the outer loop so that j is size_t and goes from 0 to newVectorTwo.size() (exclusive).

    Keep in mind that erase also invalidates iterators at and after the point of erasure, so your inner loop is undefined behavior if it actually erases anything (other than the last element, since in that case the loop exits immediately after) - so the approach of using j as an incrementing iterator generally won't work as you have it. Using an index into the vector solves that: you have no reference to iterators at all except the temporary one created by begin().

    Performance

    The performance of your solution will be very poor for vectors of any significant size. The two nested loops and the erase call make it an O(n^3) solution (more specifically O(m*n^2) if v1 and v2 have sizes m and n respectively).

    A simpler solution would be just to create newVectorTwo initially empty, and then add each element with push_back which is not a duplicate, rather than trying to remove duplicates from a fully populated vector. This push_back runs in O(1) amortized time, this will at reduce it to O(n^2). You could also just get rid of newVectorTwo and append elements directly to newVectorOne and return that. You'd need to change your outermost iteration to use an index though, to get around iterator invalidation.

    If you want an expected O(n) (actually O(n + m)) solution, you could populate a std::unordered_map with the contents of v1 and use that for your lookup, rather than use the two nested loops.