8

I currently am migrating a large code base from

  • Visual Studio 2013 (v120)
  • C++11

to

  • Visual Studio 2019 (v142)
  • C++17

and now, my tests fail in strange places - I get index out of bounds crashes and other strange changes in behavior. Upon digging I noticed that the following code:

#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<int>> nestedVector;
    nestedVector.insert(nestedVector.begin(), {});
    std::cout << nestedVector.size() << " elements";
}

produces a one-element vector in VS2013 but an empty vector in VS2019.

Other ways of inserting

nestedVector.insert(nestedVector.begin(), std::vector<int>{});
nestedVector.insert(nestedVector.begin(), std::vector<int>());

work in both setups and properly add a new element. What is happening here?

PhilLab
  • 4,777
  • 1
  • 25
  • 77
  • 4
    Makes sense, since `insert` has an overload taking `std::initializer_list` (see [this](https://en.cppreference.com/w/cpp/container/vector/insert)). I'm not sure why VS 2013 doesn't use it. Does something like `nestedVector.insert(nestedVector.begin(), {1,2,3});` work in VS 2013? – HolyBlackCat Jul 13 '19 at 07:46
  • 1
    VS 2013 did not implementation C++11 initializer list. The RTM release accidentally included an ``initializer_list`` header, but it was non-functional. – Chuck Walbourn Jul 13 '19 at 07:49
  • 1
    Funny, so now we've also the visual ambiguity between a single empty vector or an empty initializer list? – 6502 Jul 13 '19 at 07:54
  • Wow. In 2013, `nestedVector.insert(nestedVector.begin(), { 1,2,3 })` works but stepping trough it I see first the move and then the call to `insert(const_iterator _Where, _Ty&& _Val)`. Still in 2013, when stepping through this: `std::vector foo; std::string b; foo.insert(options.end(), { "a", b });`, I see it jumping into `iterator insert(const_iterator _Where, _XSTD initializer_list _Ilist)`, so the initializer_list seems to be implemented – PhilLab Jul 13 '19 at 08:24
  • 1
    Not an explanation, but you may want to look into `emplace`. – Marc Glisse Jul 13 '19 at 09:01
  • 2
    @HolyBlackCat Very interesting comments, would one of them qualify as answer? – PhilLab Jul 23 '19 at 12:37
  • @PhilLab If HolyBlackCat and ChuckWalbourn don't want to write an answer, please write an answer yourself and accept it. Then this question will be marked as answered, which helps keeping the site cleaner. – Werner Henze May 02 '20 at 18:26
  • @WernerHenze Thanks for the hint, however, I don't feel that the question has been answered definitively. A STL implementation bug is suspected but this is not confirmed. – PhilLab May 03 '20 at 06:43

1 Answers1

3

As was already mentioned in the comments, in your original program the call of nestedVector.insert(nestedVector.begin(), {}) selects the overloaded method:

iterator insert( const_iterator pos, std::initializer_list<T> ilist );

see https://en.cppreference.com/w/cpp/container/vector/insert.

Since the initializer list is empty, nothing is really inserted and the vector size is zero at the end. It is the same behavior in all compilers, demo: https://godbolt.org/z/9nnET5ren

Apparently, VS2013 did not implement this overload of insert method, so another one called:

iterator insert( const_iterator pos, const T& value );

creating one element in the vector. This is wrong behavior.

Fedor
  • 17,146
  • 13
  • 40
  • 131