6

This code:

#include <memory>
#include <vector>
#include <algorithm>

struct Foo
{
    int bar;

    Foo(const int val) :
        bar(val)
    {
    }
};

int main() {
    std::vector<std::unique_ptr<Foo>> vec;
    vec.emplace_back(std::make_unique<Foo>(42));
    Foo* ptr = vec.back().get();
    auto& it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr<Foo>& p)
    {
        return p.get() == ptr;
    });
    if (it != vec.end())
    {
        vec.erase(it);
    }

    return 0;
}

Works fine in MSVC, but errors out in GCC 5.1:

prog.cpp: In function 'int main()':

prog.cpp:19:25: error: invalid initialization of non-const reference of type '__gnu_cxx::__normal_iterator*, std::vector > >&' from an rvalue of type '__gnu_cxx::__normal_iterator*, std::vector > >' auto& it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr& p)

  1. Which compiler is bugged?
  2. How do I erase a pointer from a std::vector of std::unique_ptr correctly?
2
  • "bugged" implies it's unintentional behavior. It's not. The MSVC devs are well aware of this and have no intention of ever changing it. Commented Nov 7, 2016 at 0:17
  • 1
    However, if you want to enforce strict standards compliance (to the best of the compiler's current ability), use the /Za flag. Commented Nov 7, 2016 at 0:25

2 Answers 2

10

gcc is correct here. You can't initialize a lvalue reference with an rvalue, and you're doing it for the it reference to an iterator (std::find_if returns an rvalue)

auto& it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr<Foo>& p)
    ^

Either make it an object:

auto it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr<Foo>& p)

demo

or a const reference:

auto const& it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr<Foo>& p)

demo

Other than that, your code for erasing an element from a vector is correct

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

Comments

0

VS2015 will emit a warning that a nonstandard extension is being used if you turn on level 4 warnings /W4:

warning C4239: nonstandard extension used:
note: A non-const reference may only be bound to an lvalue

#pragma warning( push, 3 )  
#include <memory>
#include <vector>
#include <algorithm>
#pragma warning( pop ) 
#pragma warning( disable : 4710 )

struct Foo
{
    int bar;

    Foo(const int val) :
        bar(val)
    {
    }
};

int main() {
    std::vector<std::unique_ptr<Foo>> vec;
    vec.emplace_back(std::make_unique<Foo>(42));
    Foo* ptr = vec.back().get();
    auto& it = std::find_if(vec.begin(), vec.end(), [&](std::unique_ptr<Foo>& p)
    {
        return p.get() == ptr;
    });
    if(it != vec.end())
    {
        vec.erase(it);
    }

    return 0;
}

Produces:

1>c:\users\flatmouse\documents\visual studio 2015\projects\project79\project79\source.cpp(25): warning C4239: nonstandard extension used: 'initializing': conversion from 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<std::unique_ptr<Foo,std::default_delete<_Ty>>>>>' to 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<std::unique_ptr<Foo,std::default_delete<_Ty>>>>> &'
1>          with
1>          [
1>              _Ty=Foo
1>          ]
1>  c:\users\flatmouse\documents\visual studio 2015\projects\project79\project79\source.cpp(25): note: A non-const reference may only be bound to an lvalue

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.