c++ 对象的可选引用:最好的方式?

xtfmy6hx  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(130)

我想要一个函数返回一个对象的可选引用。想法是避免复制,但似乎我不应该使用根据这个讨论:std::optional specialization for reference types
假设我有一个对象的Map,我希望我的函数返回一个对象的引用,如果它存在于Map中。最好的方法是什么?

  1. struct HeavyObj;
  2. std::map<int, HeavyObj> my_map;
  3. std::optional<HeavyObj&> get_obj(int key){
  4. if(auto it = my_map.find(key); it != my_map.end()){
  5. return std::optional<HeavyObj&>{ ? };
  6. } else {
  7. return {};
  8. }

ps:需要C++17
update,如果我使用指针,我得到:

  1. #include <optional>
  2. #include <map>
  3. struct HeavyObj{
  4. int data;
  5. };
  6. static std::map<int, HeavyObj> my_map;
  7. std::optional<HeavyObj*> get_obj(int key){
  8. if(auto it = my_map.find(key); it != my_map.end()){
  9. return std::optional<HeavyObj*>{&(*it)};
  10. } else {
  11. return {};
  12. }
  13. }
  14. int main(){
  15. auto test = get_obj(3);
  16. return 0;
  17. }
  18. // gcc -std=c++17 -Wall optional.cc -lstdc++
  19. optional.cc: In function std::optional<HeavyObj*> get_obj(int)’:
  20. optional.cc:13:47: error: no matching function for call to std::optional<HeavyObj*>::optional(<brace-enclosed initializer list>)’
  21. 13 | return std::optional<HeavyObj*>{&(*it)};
  22. | ^
  23. ```
wz8daaqr

wz8daaqr1#

如前所述,您可以使用未初始化的指针为nullptr这一事实来模拟optional行为。
然而,有些人可能会认为使用optional更干净,因为如果你有一个类似的函数返回optionalint,那么它会更一致。
如果没有找到值,可以使用std::nullopt,如果找到了,只需返回值(编译器将执行从HeavyObject* 到可选<HeavyObject*>的转换,但您可以手动执行)。

uqxowvwt

uqxowvwt2#

返回一个HeavyObj*,这是惯用的解决方案。C++标准库在许多地方返回充当可选引用的指针。例如:

  • std::get_if(std::variant)
  • std::any_cast<T*>(std::any*)

这两个都是C++17函数,所以它们绝不是90年代的过时设计。在你的例子中,我们可以使用原始指针如下:

  1. HeavyObj* get_obj(int key){
  2. if(auto it = my_map.find(key); it != my_map.end()){
  3. return std::addressof(*it);
  4. } else {
  5. return nullptr;
  6. }
  7. }
  • 注意:如果HeavyObj有一个重载的address-of运算符,我们将使用std::addressof。*

std::optional问题

std::optional<HeavyObj*>有点问题,因为它在两个方面是可选的:

  • std::optional可以不保存值,或者
  • 内部HeavyObj*可以是nullptr

您只需要一个可选层,因此使用HeavyObj*
如果你 * 拼命 * 想避免原始指针,那么解决办法是:

  1. std::optional<std::reference_wrapper<HeavyObj>> get_obj(int key){
  2. if(auto it = my_map.find(key); it != my_map.end()){
  3. return std::ref(*it);
  4. } else {
  5. return {};
  6. }
  7. }

但是,这不是很符合人体工程学,因为返回类型是令人难以置信的长。

展开查看全部

相关问题