Продолжая штудировать C++11 FAQ Бьёрна Страуструпа обнаружил маленькую ошибку в двух примерах кода:
Это в разделе "Algorithms improvements".
Смысл проблемы в том, что нет смысла в попытке сортировать контейнер unique_ptr-ов посредством функтора, получающего свои аргументы по значению. В этом в принципе нет смысла, т.к. при копировании unique_ptr по значению должен происходить перенос владения из старого unique_ptr в новый, т.е. владение должно было бы быть передано аргументам функтора после чего объекты были бы разрушены при выходе из функтора.
Именно потому, что в этом в принципе нет смысла, в std::unique_ptr конструктор и оператор копирования, получающие в качестве аргумента константную ссылку на std::unique_ptr, помечены как delete, т.е. запрещены к использованию. Именно поэтому, если у нас есть:
void f(std::unique_ptr<Big> a) {...}
Мы не можем написать так:
std::unique_ptr<Big> b(...);
f(b);
А должны писать одним из следующих способов:
f(std::move(b)); // Явное преобразование к rvalue reference.
// После этой конструкции b уже ничего не контролирует,
// владение объектом Big передано аргументу функции f().
f(std::unique_ptr<Big>(new Big(...))); // Неявный rvalue reference.
// Для конструирования аргумента a функции f()
// вызывается move constructor для std::unique_ptr.
Поэтому код из примеров Страуструпа не скомпилируется. Для того, чтобы функторы работали так, как задумывалось, из прототипы должны были бы быть объявлены вот так:
template<class P> struct Cmp { // compare *P values
bool operator() (const P & a, const P & b) const { return *a<*b; }
}
и
sort(vb.begin(),vb.end(),
[](const unique_ptr<Big> & a, const unique_ptr<Big> & b) { return *a<*b; });
Под катом автономный пример, с которым можно поиграться самостоятельно.
#include <vector> #include <memory> #include <algorithm> #include <iostream> #include <string> class My { public : My( std::string s ) : s_( std::move( s ) ) { std::cout << "M('" << s_ << "')" << std::endl; } ~My() { std::cout << "~M('" << s_ << "')" << std::endl; } const std::string & get() const { return s_; } private : const std::string s_; }; template< class P > struct Cmp { bool operator()( const P & a, const P & b ) const { return a->get() < b->get(); } }; int main() { std::vector< std::unique_ptr< My > > v; v.emplace_back( std::unique_ptr< My >( new My( "One" ) ) ); v.emplace_back( std::unique_ptr< My >( new My( "Two" ) ) ); v.emplace_back( std::unique_ptr< My >( new My( "Three" ) ) ); v.emplace_back( std::unique_ptr< My >( new My( "Four" ) ) ); std::cout << "sorting..." << std::endl; std::sort( v.begin(), v.end(), []( const std::unique_ptr< My > & a, const std::unique_ptr< My > & b ) { return a->get() < b->get(); } ); std::sort( v.begin(), v.end(), Cmp<std::unique_ptr<My> >() ); std::cout << "sorting result: " << std::endl; for( auto & s : v ) std::cout << s->get() << std::endl; } |
Комментариев нет:
Отправить комментарий