C++ 如何对传出引用进行编码,以便在具有唯一\u ptr的容器上进行搜索
我试图替换一个函数,该函数搜索指针容器,并使用C++ 如何对传出引用进行编码,以便在具有唯一\u ptr的容器上进行搜索,c++,reference,containers,unique-ptr,C++,Reference,Containers,Unique Ptr,我试图替换一个函数,该函数搜索指针容器,并使用unique\u ptr将找到的元素作为传出引用 下面是一个简单的示例,演示使用普通指针时的情况: bool find_ref_in_list(int n, const std::list<int*>&l, int*& element) { auto iter = find_if(l.begin(), l.end(), [n](int* x) { return (*x == n) ? tru
unique\u ptr
将找到的元素作为传出引用
下面是一个简单的示例,演示使用普通指针时的情况:
bool find_ref_in_list(int n, const std::list<int*>&l, int*& element)
{
auto iter = find_if(l.begin(), l.end(), [n](int* x)
{
return (*x == n) ? true : false;
});
element = *iter;
return true;
}
在这种情况下,我不打算共享元素的所有权,因此shared\u ptr
不是一个选项。此外,我不想获得所有权,因此移动操作不是一个好主意
我知道我可以简单地使用迭代器作为传出引用,或者使用get()
的原始指针,但我认为这会在某种程度上阻碍惟一ptr的概念
因此,问题是,是否有可能为唯一的_ptr提供传出引用,或者哪种技术是将此问题编码为唯一的_ptr的正确技术。我正在寻找一个解决方案,它不使用第三方库,如boost
我不打算共享元素的所有权,因此shared\u ptr
不是一个选项。另外,我不想取得所有权,所以搬家不是一个好主意
当前流行的惯例是,原始指针只是一个观察者。它不参与对象的任何类型的所有权。它也不应该存储在任何可能比它指向的对象更长寿的地方。在这种情况下使用原始指针是可以的(事实上,许多人建议使用原始指针来实现这一点)。因此,无论何时在API中使用原始指针,它都应该是非所有者指针,只提供对其他人拥有的对象的访问
但是,如果您希望能够为调用方提供实际参与所有权的选项,则需要切换到共享\u ptr
。但是根据您所说的,您只想返回一个短暂的观察者指针,所以只需使用一个原始指针
赫伯·萨特(Herb Sutter)有一篇关于这方面的好文章:
(离题)
顺便说一下,您可以直接返回int*
而不是bool
,而不必使用out参数。如果未找到元素,则返回nullptr
。因此,您的函数签名将是:
int* find_ref_in_list(int n, const std::list<int*>&l);
int*在列表中查找引用(int n,const std::list&l);
因此,问题是,是否有可能为唯一的_ptr提供传出引用,或者哪种技术是将此问题编码为唯一的_ptr的正确技术
你发明了自己的术语外向参考
,并用它愚弄自己。您的代码中没有传出引用
,只需通过引用返回值。返回值时,如果不失去所有权,则无法返回std::unique_ptr
。要返回引用,必须将其用作返回值,例如:
int*& find_ref_in_list(int n, const std::list<int*>&l, bool &found)
int*&在列表中查找引用(int n,const std::list&l,bool&found)
但现在您有了不同的问题,当找不到项并且函数使用困难时,返回什么。无法通过参数返回引用,因为不存在对引用的引用。因此,如果您想共享所有权,可以按值返回原始指针,或者std::shared_ptr
。在发明自己的术语时要小心,否则你就无法理解那里到底发生了什么。
element = *iter; // causes error because assignment operator=
您试图不使引用元素
指向*iter
,而是分配引用的内容(在您的情况下为std::unique_ptr)。顺便说一句,const
也有一个问题
有两种可能的解决办法:
通过指针将元素传递到唯一的\u ptr:
您必须检查std::find_if语句的返回值。返回值iter==l.end()
表示搜索失败,函数可能返回false。如果迭代器有效,则应重置元素以获取新的所有权,函数可通过返回true终止
bool find_ref_in_list(int n, const std::list<std::unique_ptr<int>>&l, std::unique_ptr<int>& element)
{
auto iter = std::find_if(l.begin(), l.end(), [n](const std::unique_ptr<int>& x)
{
return (*x == n) ? true : false;
});
if (iter == l.end()){
element.reset(nullptr);
return false;
}
element.reset(iter->get());
return true;
}
bool find_ref_in_list(int n,const std::list&l,std::unique_ptr&element)
{
自动iter=std::find_if(l.begin(),l.end(),[n](const std::unique_ptr&x)
{
返回(*x==n)?真:假;
});
如果(iter==l.end()){
元素重置(空PTR);
返回false;
}
元素重置(iter->get());
返回true;
}
返回(*x==n)?真:假代码>看起来像是代码混淆请参见此。我发现我没有添加未找到值的情况。所以实际上应该有一个if(iter==l.end())返回false代码>就在元素赋值之前。尝试元素.reset(iter->get())代码>代替元素=*iter代码>@seccpur实际上这是一个很好的方法。也许你更应该把它作为一个答案而不是一个评论,因为它确实满足了所有的要求。你用std::reference\u wrapper
的解决方案就是我搜索的,但是我认为不可能为这种类型声明一个变量。以下代码失败:std::reference\u包装器元素代码>如果你找不到元素,你会返回什么样的引用?我在回答中已经提到了这个问题。例如,您必须抛出一个异常。我并没有说这是一个好的解决方案,我只是把它看作是一个可行的解决方案。但你最好不要那样做。关键是,在您的情况下,您并没有传出引用,您只是使用引用作为一种机制返回值。当您返回指向int
的值类型指针时,您很好,当您尝试返回类型std::unique\u ptr
的值时,您有明显的问题。在未找到项的情况下直接返回int*
和nullptr
比std::optional
@Slava yes更简单。我想得太多了:-)对不起。当你把它作为一个评论贴在上面时,我对这个方法很满意,因此建议你把它作为一个答案贴在上面。然而
bool find_ref_in_list(int n, const std::list<std::unique_ptr<int>>&l, const std::unique_ptr<int>* element)
{
auto iter = std::find_if(l.begin(), l.end(), [n](const std::unique_ptr<int>& x)
{
return (*x == n) ? true : false;
});
element = &*iter;
return true;
}
bool find_ref_in_list(int n, const std::list<std::unique_ptr<int>>&l, std::reference_wrapper<const std::unique_ptr<int>>& element)
{
auto iter = std::find_if(l.begin(), l.end(), [n](const std::unique_ptr<int>& x)
{
return (*x == n) ? true : false;
});
element = std::ref(*iter);
return true;
}
bool find_ref_in_list(int n, const std::list<std::unique_ptr<int>>&l, std::unique_ptr<int>& element)
{
auto iter = std::find_if(l.begin(), l.end(), [n](const std::unique_ptr<int>& x)
{
return (*x == n) ? true : false;
});
if (iter == l.end()){
element.reset(nullptr);
return false;
}
element.reset(iter->get());
return true;
}