2016-11-06 3 views
3

Этот код:Ошибка компиляции при попытке find_if в unique_ptr в векторе

#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; 
} 

отлично работает в MSVC, но ошибки вне в 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. Какой компилятор прослушивается?
  2. Как удалить указатель из std::vector из std::unique_ptr правильно?
+0

«прослушивание» подразумевает непреднамеренное поведение. Это не. Разработчики MSVC хорошо знают об этом и не намерены его менять. –

+1

Однако, если вы хотите обеспечить соблюдение строгого соответствия стандартов (в лучшем случае из имеющихся возможностей компилятора), используйте флаг ['/ Za'] (https://msdn.microsoft.com/en-us/library/0k0w269d. ASPX). –

ответ

4

gcc верен здесь. Вы не можете инициализировать Lvalue ссылки с RValue, и вы делаете это для it ссылки на итератор (std::find_if, возвращает RValue)

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

Либо сделать его объект:

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

demo

или константная ссылка:

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

demo

Кроме этого, ваш код для стирания элемента из вектора является правильным

0

VS2015 будет выдавать предупреждение о том, что нестандартное расширение используется, если вы включите уровень 4 предупреждения /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; 
} 

Производит:

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