1

Let's take this simplified example:

std::vector< int > v;
v.push_back( 1 );
v.insert( v.end()-1, v[ v.size()-1 ] ); // the problem is on this line

// We output the vector
std::for_each( v.begin(), v.end(), []( const int& e_ ){ std::cout<<e_<<std::endl; } );

output:

-17891602
1

The author of the code intended to insert a duplicate of the last element before the end of the vector. There are several good ways to to this but the author decided to use this one.

It worked as "expected" before C++11. That is because in the microsoft implementation of the insert in a vector, they make a copy of the value to insert in case the value inserted is in the range of the vector.

Now with C++11, there is a version of insert taking a r-value reference which do not need to do this trick because it's a temporary anyway.

But surprisingly, using the code above, the compiler decides to take the r-value ref version instead of the by-reference version, which inserts a uninitialized value before the end of the vector. Note that the operator[] returns by reference.

Why does the compiler chose to take the version by r-value reference?

  • I don't know much about r-values but using v.end() which returns an iterator as an index seems like **a** problem if not **the** problem you're experiencing. use `push_back` instead. – ArnonZ Aug 13 '14 at 15:39
  • 1
    I vaguely remember STL saying on reddit that `push_back` of an element of a `vector` should work, but currently doesn't with Microsoft's implementation. Could be the same issue. – Baum mit Augen Aug 13 '14 at 15:41
  • 1
    @BaummitAugen [this one?](http://www.reddit.com/r/cpp/comments/vog1p/a_commonly_unknown_stdvector_pitfall/) related: http://stackoverflow.com/q/24908718 – dyp Aug 13 '14 at 15:42
  • 1
    Note that the `v.insert` call is not adding an extra member at the end of the list. Instead, it's inserting it one before the end, which in this case is the front of the list. – Bill Lynch Aug 13 '14 at 15:42
  • 1
    Ah, and STL linked the NAD LWG issue: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526 This is guaranteed to work. – dyp Aug 13 '14 at 15:45
  • I tested your code using VS2013 Express, it calls the `reference` version of `operator[]` and the `const _Ty& _Val` version of `insert`. Didnt happen the r-value version. – Marson Mao Aug 13 '14 at 16:02
  • Why do you believe the compiler is calling the rvalue reference version? Can you provide assembly or disassembly demonstrating this? – ecatmur Aug 13 '14 at 16:04
  • @ecatmur OP said he had stepped inside `insert` in the comment below (of the current answer). – Marson Mao Aug 13 '14 at 16:08
  • @MarsonMao so that's assuming that the debugger is reporting the code location correctly. I think it's more likely that the debugger is incorrect than that the compiler is choosing the wrong overload. – ecatmur Aug 13 '14 at 16:11
  • Yes by stepping, I was really surprised that the debugger entered the && version of insert, which explains why the first element of my vector is uninitialized. But I'm pretty sure now it's a compiler problem. Since other people tested with more recent versions of the MS compiler and with other compilers. ( BTW I'm using VS2010 SP1Rel ) – Jean-Simon Brochu Aug 13 '14 at 16:11
  • 1
    an off-topic comment, why is this question not-related-to-STL? I saw that the tag was removed...wondering why. – Marson Mao Aug 13 '14 at 16:15
  • -17891602 is 0xFEEEFEEE, which means your first element is freed, hmmm interesting lol – Marson Mao Aug 13 '14 at 16:16
  • @Jean-SimonBrochu Requesting a `move` for an `int` will perform just a copy. Therefore, this is probably not the problem, albeit weird. – dyp Aug 13 '14 at 17:44
  • @dyp : You'll have to dig into the _Insert_n implementation of Microsoft to understand the problem with the r-value ref version. Or read the entire thread. – Jean-Simon Brochu Aug 14 '14 at 15:10

2 Answers2

4

It sounds like you may be experiencing a bug, either in the vector implementation, or in your own code. However I do not see a bug in what you have posted. Here is a completed example of your post:

#include <iostream>
#include <vector>

template <class Iter>
void
display(Iter first, Iter last)
{
    std::cout << "{";
    if (first != last)
    {
        std::cout << *first;
        for (++first; first != last; ++first)
            std::cout << ", " << *first;
    }
    std::cout << "}\n";
}

template <class C>
void
display(const C& c)
{
    display(c.begin(), c.end());
}

int
main()
{
    std::vector< int > v;
    v.push_back( 1 );
    v.insert( v.end()-1, v[ v.size()-1 ] );
    display(v);
}

which for me outputs:

{1, 1}

That is, in the implementation I am using (libc++), the lvalue overload of insert is being chosen.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
0

It turns out it is a problem with VS 2010 compiler that has been fixed with the 2013 compiler. I don't know which one between those 2 versions exactly but it calls the r-value reference version using VS2010 SP1 and the l-value version with VS2013 Update 3 which is the expected behavior.

As you can see in the comments above, some people have tested the code using other compilers than Microsoft's compilers and it also works as expected.

EDIT : I found another post about the same problem. It is a combination of templates, const& and &&: Visual C++ 2010, rvalue reference bug?

Community
  • 1
  • 1