排序unique_ptrs列表

时间:2018-05-20 20:51:42

标签: c++ smart-pointers

以下代码无法编译:

bool ptrLess(unique_ptr<int> ptr1, unique_ptr<int> ptr2)
{
   return *ptr1 < *ptr2;
}

int main()
{
   unique_ptr<int> ptr1(new int(3));
   unique_ptr<int> ptr2(new int(2));
   unique_ptr<int> ptr3(new int(5));
   list<unique_ptr<int>> list;

   list.push_back(ptr1);
   list.push_back(ptr2);
   list.push_back(ptr3);

   list.sort(ptrLess);

   for (auto &element : list) {
      cout << *element;
   }

   return 0;
}

我认为这是因为删除了unique_ptr的复制构造函数。我得到一个错误:

  

错误C2280:   “的std ::的unique_ptr&GT; ::的unique_ptr(常量   的std ::的unique_ptr&LT; _Ty,性病:: default_delete&LT; _Ty&GT;&GT; &amp;)':试图   引用已删除的功能

有没有办法对unique_ptr的列表进行排序,可能是使用移动构造函数?

4 个答案:

答案 0 :(得分:5)

你应该使用const ref - 毕竟你不想修改这些指针:

bool ptrLess(const unique_ptr<int>& ptr1, const unique_ptr<int>& ptr2)

如果您的list模板为std::list,那么将参数作为r值参考传递无法正常工作 - list::sort必须致电std::move才能有效地重置您的指针。

修改

至于列表的其余代码:std::list有一个名为emplace_back(和emplace_front)的方便方法,它允许您在原地构建和附加元素:

your_list.emplace_back(new int(2));

答案 1 :(得分:1)

试试这个:

#include <memory>
#include <list>
#include <iostream>
using namespace ::std;

bool ptrLess(unique_ptr<int>& ptr1, unique_ptr<int>& ptr2)
{
   return *ptr1 < *ptr2;
}

int main()
{
   unique_ptr<int> ptr1(new int(3));
   unique_ptr<int> ptr2(new int(2));
   unique_ptr<int> ptr3(new int(5));
   list<unique_ptr<int>> list;

   list.push_back(move(ptr1));
   list.push_back(move(ptr2));
   list.push_back(move(ptr3));

   list.sort(ptrLess);

   for (auto &element : list) {
      cout << *element;
   }

   return 0;
}

这里的问题是你需要了解unique_ptr实际上的目标:

当处理指针/引用时,如果存在指向同一对象的多个指针/引用,则会出现很多潜在的问题。 unique_ptr试图避免这种情况。 因此,您无法创建引用同一对象的2 unique_ptr

您无法使用ptrLess()功能,因为将其称为

   unique_ptr<int> ptr1(new int(3));
   unique_ptr<int> ptr2(new int(2));

   ptrLess(ptr1, ptr2);

因为这意味着ptr1 ptr2必须被复制并传递给ptrLess() - 这里的关键字是&#39;按值调用&#39;。< / p>

而且,你做不到

   list<unique_ptr<int>> list;
   unique_ptr<int> ptr1(new int(3));

   unique_ptr<int> ptr1(new int(3));

因为这也是必须创建ptr1的副本。 这里的解决方案是不将unique_ptr s作为值传递给ptrLess,而是作为参考:

bool ptrLess(unique_ptr<int>& ptr1, unique_ptr<int>& ptr2);

你没有将副本传递到列表中,但移动你的对象:

list.push_back(move(ptr1));
这里的

关键字是&#39; move-semantics&#39;。 这将使ptr1变量的内容无效 - 该对象已从ptr1移出到列表中。

如果您对这些事情更感兴趣,我建议您查看Rust语言;)

正如Baum mit Augen指出的那样,ptrLess的参数最好被声明为const

bool ptrLess(const unique_ptr<int>& ptr1, const unique_ptr<int>& ptr2);

答案 2 :(得分:-1)

尝试传递const ref,这样就不会复制参数: bool ptrLess(const unique_ptr&amp; ptr1,const unique_ptr&amp; ptr2){return * ptr1&lt; * PTR2; }

答案 3 :(得分:-1)

我认为,如果OP使用shared_ptr代替unique_ptr,那么原先发布的代码将以其他方式保持不变:

#include <memory>
#include <list>
#include <iostream>
using namespace ::std;

bool ptrLess(const shared_ptr<int>& ptr1, const shared_ptr<int>&  ptr2)
{
   return *ptr1 < *ptr2;
}

int main()
{
   shared_ptr<int> ptr1(new int(3));
   shared_ptr<int> ptr2(new int(2));
   shared_ptr<int> ptr3(new int(5));
   list<const shared_ptr<int>> list;

   list.push_back(ptr1);
   list.push_back(ptr2);
   list.push_back(ptr3);

   list.sort(ptrLess);

   for (auto &element : list) {
      cout << *element;
   }

   return 0;
}

Wandbox上运行。

从某种意义上说,这是一种一贯的做事方式。 push_back通常会复制正在添加到列表中的对象,如果原始对象仍然可以使用,则他或她想要使用它。使用shared_ptr具有类似的语义,而没有复制对象本身的开销。相反,只复制shared_ptr,这是一个便宜的操作。

此外,将OP的原始代码修改为move unique_ptrs进入列表本身就很脆弱。它们仍然在调用者的范围内,但不再可用。如果你尝试,你会得到(我假设)nullptr解除引用。那么,最好这样做(注意额外的括号):

...

list<unique_ptr<int>> list;

{
   unique_ptr<int> ptr1(new int(3));
   unique_ptr<int> ptr2(new int(2));
   unique_ptr<int> ptr3(new int(5));

   list.push_back(move(ptr1));
   list.push_back(move(ptr2));
   list.push_back(move(ptr3));
}

...

现在你很安全。

在那里,这是一个比原版更好的帖子,对不起。