对unique_ptrs列表进行排序



以下代码将无法编译:

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>::unique_ptr(const std::unique_ptr<_Ty,std::d efault_delete<_Ty>> &(': try to 引用已删除的函数

有没有办法对unique_ptr的列表进行排序,也许是使用 move 构造函数?

你应该使用 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));

试试这个:

#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()- 这里的关键字是"按值调用"。

而且,你不能做

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

因为这也必须创建一个副本ptr1. 这里的解决方案是不要将unique_ptr传递给ptrLess作为值,而是作为引用:

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

而且您不会将副本传递到列表中,而是将对象移动到那里:

list.push_back(move(ptr1));

这里的关键词是"移动语义"。 这将使ptr1变量的内容无效 - 对象已从ptr1移动到列表中。

我建议看看 Rust 语言,如果你对这些东西更感兴趣;)

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

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

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

我突然建议,如果 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 的原始代码以将unique_ptrsmove到列表中本质上是脆弱的。 它们仍保留在调用方的范围内,但不再可用。 如果您尝试,您将获得(我假设(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));
}
...

现在你安全了。

在那里,这是一个比原始版本好得多的帖子,对此感到抱歉。

相关内容

  • 没有找到相关文章

最新更新