提问人:mu5e 提问时间:6/20/2023 最后编辑:mu5e 更新时间:6/20/2023 访问量:184
对对象的可选引用:最佳方式?
optional refence to an object: best way?
问:
我希望函数返回对对象的可选引用。想法是避免复制,但似乎我不应该根据这个讨论使用: std::可选的引用类型专用化
假设我有一个对象的映射,我希望我的函数返回对对象的引用(如果映射中存在该对象)。最好的方法是什么?
struct HeavyObj;
std::map<int, HeavyObj> my_map;
std::optional<HeavyObj&> get_obj(int key){
if(auto it = my_map.find(key); it != my_map.end()){
return std::optional<HeavyObj&>{ ? };
} else {
return {};
}
ps:C++17 需要
更新,如果我使用指针,我得到:
#include <optional>
#include <map>
struct HeavyObj{
int data;
};
static std::map<int, HeavyObj> my_map;
std::optional<HeavyObj*> get_obj(int key){
if(auto it = my_map.find(key); it != my_map.end()){
return std::optional<HeavyObj*>{&(*it)};
} else {
return {};
}
}
int main(){
auto test = get_obj(3);
return 0;
}
// gcc -std=c++17 -Wall optional.cc -lstdc++
optional.cc: In function ‘std::optional<HeavyObj*> get_obj(int)’:
optional.cc:13:47: error: no matching function for call to ‘std::optional<HeavyObj*>::optional(<brace-enclosed initializer list>)’
13 | return std::optional<HeavyObj*>{&(*it)};
| ^
```
答:
0赞
UnquoteQuote
6/20/2023
#1
如前所述,您可以使用未初始化的指针这一事实来模拟该行为。nullptr
optional
但是,有些人可能会认为它无论如何都使用起来更干净,因为如果您有一个类似的函数返回一个,例如,它会更加一致。optional
optional
int
当找不到该值时,您可以使用 ,如果找到该值,则直接返回该值(编译器将执行从 HeavyObject* 到 optional<HeavyObject* 的强制转换>但您可以手动执行)。std::nullopt
评论
0赞
Evg
6/20/2023
std::optional<T*
在这种情况下,>是错误接口的一个例子。从逻辑上讲,有两种类型的返回值 - 指向找到对象的指针和对应于丢失对象的某个值。 保存三种状态(空可选、空指针和非空指针),而不是两种。所以它不是一个更干净的退货类型,它只是一个错误的退货类型。std::optional<T*>
0赞
UnquoteQuote
6/20/2023
我同意你的看法,不会那样使用它。但纯粹主义者可能会说,指针应该始终初始化。无论如何,我认为展示如何使用可选很重要,但我认为你的观点也很重要,因为在实践中它只是浪费资源。
3赞
Retired Ninja
6/20/2023
“未初始化的指针是” 不,它不是,它是一个未初始化的指针,其值不确定。 可以指向任何地方。 初始化为 。nullptr
int *p;
int *p = nullptr;
nullptr
1赞
Evg
6/20/2023
纯粹主义者可能会说,指针应该始终被初始化 - 是指针最纯粹的初始化。;)指针本身的想法可以为空。nullptr
0赞
Jan Schultke
6/20/2023
#2
返回 a ,它是惯用的解决方案。C++ 标准库返回指针,这些指针在许多地方充当可选引用。例如:HeavyObj*
std::get_if(std::variant)
std::any_cast<T*>(std::any*)
这些都是C++17函数,所以它们绝不是90年代的过时设计。 在您的情况下,我们可以按如下方式使用原始指针:
HeavyObj* get_obj(int key){
if(auto it = my_map.find(key); it != my_map.end()){
return std::addressof(*it);
} else {
return nullptr;
}
}
注意:我们使用 std::addressof
,以防 HeavyObj
有一个过载的 address-of 运算符。
问题std::optional
std::optional<HeavyObj*>
会有点问题,因为它在两个方面是可选的:
- 可能没有价值,或者
std::optional
- 里面可能是一个
HeavyObj*
nullptr
您只需要一层可选性,因此请使用 .HeavyObj*
如果您迫切希望避免使用原始指针,那么解决方案将是:
std::optional<std::reference_wrapper<HeavyObj>> get_obj(int key){
if(auto it = my_map.find(key); it != my_map.end()){
return std::ref(*it);
} else {
return {};
}
}
但是,这并不是很符合人体工程学,因为返回类型非常长。
评论
HeavyObj*
或std::optional<std::reference_wrapper<HeavyObj>>
HeavyObj *
nullptr
HeavyObj
it->second
*it