Why in this code the compiler chooses the r-value

2019-08-15 06:46发布

问题:

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?

回答1:

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.



回答2:

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?



标签: c++ c++11 vector