0

I am simply trying to concatenate a vector to itself but the following code is not working and I am not able to find the issue. If my input vector is {1,2,1}, the o/p I am getting is {1,2,1,1,16842944,1}. Please tell where I am wrong. The output I want is [1,2,1,1,2,1]

 vector<int> getConcatenation(vector<int>& nums) {
        
        int size=nums.size();
        auto itr=nums.begin();

        while(size--)
        {

            nums.push_back(*itr);
             itr++;
        }
        
        return nums;      
    }
6
  • 2
    Read about iterator invalidations. If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Commented Dec 2, 2021 at 7:04
  • 1
    You can read in brief here. Commented Dec 2, 2021 at 7:06
  • 1
    If the vector needs to update the capacity then all iterators will become invalid. You need another way to concatenate elements. Commented Dec 2, 2021 at 7:06
  • 1
    push_back can invalidate all iterators. en.cppreference.com/w/cpp/container/vector/push_back You could use indices instead or reserve enough space so reallocation isn't required. Commented Dec 2, 2021 at 7:06
  • 1
    Simple solution one: Use indexes instead of iterators for the loop. Simple solution two: Reserve memory so the capacity will be set before the loop. Commented Dec 2, 2021 at 7:09

2 Answers 2

2

In your original program push_back invalidates the iterators and using those invalidated iterators can lead to undefined behavior.

One way to solve this would be to use std::copy_n with std::vector::resize as shown below:

 vector<int> getConcatenation(vector<int>& nums) {
        
       std::vector<int>::size_type old_Size = nums.size();
       nums.resize(2 * old_Size);
       std::copy_n(nums.begin(), old_Size, nums.begin() + old_Size);
        
        return nums; //NO NEED for this return since the function took vector by reference and so the change is already reflected on passed vector     
    }

Also you would need to add #include <algorithm> for std::copy_n.

Note that since your function takes the vector be reference, there is no need to return nums because the changes you do on nums is already reflected on the original vector. So you can use void as the return type of the function and then remove the return statement.

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

Comments

1

The problem, as has been thoroughly pointed out, is that the vector reallocates its storage while the modifications are being done. There are at least three general approaches to this.

First, use an index instead of an iterator:

vector<int> getConcatenation(vector<int>& nums) {
    int size = nums.size();
    for (int i = 0; i < size; ++i)
        nums.push_back(nums[i]);
    return nums;
}

Second, use an iterator but ensure that the vector doesn't have to reallocate:

vector<int> getConcatenation(vector<int>& nums) {
    int size = nums.size();
    nums.reserve(2 * size);
    auto itr = nums.begin();
    while (--size)
        nums.push_back(*itr++);
    return nums;
}

(and that approach includes less labor-intensive things like using a builtin algorithm that copies based on iterators)

Third, unless you have to modify the input argument, just build a vector that's the right size and copy into it:

vector<int> getConcatenation(const vector<int>& nums) {
    vector<int> result(2 * nums.size());
    std::copy(nums.begin(), nums.end(), result.begin());
    std::copy(nums.begin(), nums.end(), result.begin() + nums.size());
    return result;
}

1 Comment

@RetiredNinja -- thanks. Fixed.

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.