【问题标题】:sorting a vector of std::pair<int, std::unique_ptr<const T> > depending on pair.first根据 pair.first 对 std::pair<int, std::unique_ptr<const T> > 的向量进行排序
【发布时间】:2019-01-01 09:49:45
【问题描述】:

我正在尝试对包含 const 对象的智能指针的对向量进行排序。我试图仅根据第一个对象进行排序。下面你会看到(我无数次尝试编写的)代码应该执行此操作,以及错误的摘录。

编译器抱怨 lambda 参数。我试图使参数 const、non-const、references、rvalue-references 无济于事。请帮忙?

std::pair<int, std::unique_ptr<const std::string> > a;
auto uniq = std::make_unique<const std::string>("hurz");
a = std::make_pair(1,std::move(uniq));

std::pair<int, std::unique_ptr<const std::string> > b;
uniq = std::make_unique<const std::string>("hurz");
b = std::make_pair(2,std::move(uniq));

std::vector<std::pair<int,std::unique_ptr<const std::string> > > vec;

vec.push_back(std::move(a));
vec.push_back(std::move(b));

std::sort(std::make_move_iterator(vec.begin()),
    std::make_move_iterator(vec.end()),
    []
    (const std::pair<int,std::unique_ptr<const std::string> >& i1,
     const std::pair<int,std::unique_ptr<const std::string> >& i2)
    { return i1.first > i2.first;});

错误信息对我没有帮助:

error: no matching function for call to 
'swap(std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > > > > >::value_type, 
std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > > > > >::value_type)' swap(*__a, 
*__b);
candidates are:
 /usr/include/c++/4.9/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&) 
[with _Tp = std::pair<int, std::unique_ptr<const std::basic_string<char> > >]

plus many more errors in the same vein

【问题讨论】:

  • 为什么需要std::unique_ptr&lt;const std::string&gt; 而不是简单的std::string
  • 字符串只是一个例子。我有一些我传递的对象,一旦超出范围,我想收集垃圾。
  • “我有我传递的对象......” 这表明你需要std::shared_ptr 而不是std::unique_ptr。看看他们的所有权概念。
  • 我从不同时将对象保存在两个地方,并且 shared_ptr 对我的应用程序的性能影响太大。
  • @NathanOliver Same result here

标签: c++ sorting smart-pointers move-semantics


【解决方案1】:

这里的问题是std::make_move_iterator 的使用。当您这样做时,会将迭代器转换为 move_iterator,这意味着当您取消引用它们时,您会得到 T&amp;&amp;,而不是像普通迭代器那样的 T&amp;

std::swap,在std::sort 的实现中使用它只接受左值引用,因此它不能绑定到取消引用的迭代器。如果你使用

std::sort(vec.begin(),
    vec.end(),
    []
    (const std::pair<int,std::unique_ptr<const std::string> >& i1,
     const std::pair<int,std::unique_ptr<const std::string> >& i2)
    { return i1.first > i2.first;});

相反,您将拥有std::swap 的左值来绑定,std::swap 将适用于仅移动类型

【讨论】:

  • 感谢解决方案和解释为什么它不能与 move_iterator 一起使用!
【解决方案2】:

我对@NathanOliver 的答案添加了一些进一步的解释,这对于评论来说太长了。我猜OP的使用想法

std::sort(std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end()),
    [](const std::pair<int,std::unique_ptr<const std::string> >& i1,
       const std::pair<int,std::unique_ptr<const std::string> >& i2)
       { return i1.first > i2.first;});

即,将move_iterator 应用于vector.begin(),是在排序例程中使用移动分配(而不是副本)。这个想法很诱人,但没有必要,因为在std::sort 内部,分配通常使用std::swap 其中tries to move arguments passed by reference 完成。

另一方面,对于使用输入和输出迭代器的算法,例如基本上是std::copystd::copy_ifstd::make_move_iterator 的使用可能非常有用。那些经常使用*output_it = *input_it 之类的结构,与std::make_move_iterator 一起对应*output_it = std::move(*input_it),因此可以使用*output_it 取消引用的类型的移动赋值运算符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 2020-08-03
    相关资源
    最近更新 更多