如何使用 std::reference_wrapper 将引用存储在 std::unordered_map 中?

问题描述 投票:0回答:1

我正在尝试学习

std::reference_wrapper
std::ref
的使用及其用例。

这是我编写的示例代码。请帮我解决编译错误。如果您能深入解释这个问题那就太好了。

#include <iostream>
#include <limits>
#include <unordered_map>
#include <functional>

class MyClass
{
public:
  struct Data
  {
    int id;

    Data() : id(std::numeric_limits<int>::max()) {}
  };

  std::unordered_map<std::string, Data> keyToData_;

  Data& getOrCreateData(const std::string &key) 
  {
    auto it = keyToData_.find(key);
    if (it == keyToData_.end())
    {
      it = keyToData_.insert({key, Data()}).first;
    }
    return it->second;
  }

  void addBuffer(const std::string &key, std::reference_wrapper<Data> && r)
  {
    buffer_[key] = r;
  }

private:
  std::unordered_map<std::string, std::reference_wrapper<Data>> buffer_;
};

int main(int, char **argv)
{
  MyClass dataManager{};

  auto &r1 = dataManager.getOrCreateData("key1");
  r1.id = 1;

  dataManager.addBuffer("key1", std::ref(r1));
}

我想存储数据的引用。在此期间数据会不断更新,就像数据的脏位引用一样。在程序结束时,我只需要更新这些值,而不需要迭代整个

std::unordered_map
。我不想在此过程中创建任何副本以避免性能问题,而且我也避免
std::shared_ptr
因为我认为在这种情况下使用原始指针会更好(我知道该对象不会出去范围)。

有没有更好的方法?

错误如下:

.\sample.cpp:30:16:   required from here
C:/msys64/mingw64/include/c++/11.3.0/tuple:1824:9: error: no matching function for call to 'std::reference_wrapper<MyClass::Data>::reference_wrapper()'
 1824 |         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from C:/msys64/mingw64/include/c++/11.3.0/functional:58,
                 from .\sample.cpp:4:
C:/msys64/mingw64/include/c++/11.3.0/bits/refwrap.h:321:9: note: candidate: 'template<class _Up, class, class> std::reference_wrapper<_Tp>::reference_wrapper(_Up&&) [with _Up = _Up; <template-parameter-2-2> = <template-parameter-1-2>; <template-parameter-2-3> = <template-parameter-1-3>; _Tp = MyClass::Data]'
  321 |         reference_wrapper(_Up&& __uref)
      |         ^~~~~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/11.3.0/bits/refwrap.h:321:9: note:   template argument deduction/substitution failed:
In file included from C:/msys64/mingw64/include/c++/11.3.0/bits/hashtable_policy.h:34,
                 from C:/msys64/mingw64/include/c++/11.3.0/bits/hashtable.h:35,
                 from C:/msys64/mingw64/include/c++/11.3.0/unordered_map:46,
                 from .\sample.cpp:3:
C:/msys64/mingw64/include/c++/11.3.0/tuple:1824:9: note:   candidate expects 1 argument, 0 provided
 1824 |         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from C:/msys64/mingw64/include/c++/11.3.0/functional:58,
                 from .\sample.cpp:4:
C:/msys64/mingw64/include/c++/11.3.0/bits/refwrap.h:326:7: note: candidate: 'constexpr std::reference_wrapper<_Tp>::reference_wrapper(const std::reference_wrapper<_Tp>&) [with _Tp = MyClass::Data]'
  326 |       reference_wrapper(const reference_wrapper&) = default;
      |       ^~~~~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/11.3.0/bits/refwrap.h:326:7: note:   candidate expects 1 argument, 0 provided

我尝试过像这样更改函数声明:

void addBuffer(const std::string &key, Data &r)
{
  buffer_[key] = std::ref(r);
}
c++ class c++17 pass-by-reference reference-wrapper
1个回答
2
投票

std::unordered_map::operator[]
要求
mapped_type
默认可构造。由于
std::reference_wrapper<Data>
(即
mapped_type
std::unordered_map<std::string, std::reference_wrapper<Data>> buffer_;
)不是默认可构造的,因此您会在以下行中收到编译器错误:

buffer_[key] = std::ref(r);

编译器错误将会消失,例如,一旦您使用

std::unordered_map::emplace
将键值添加到
buffer_
,这会将新元素插入到容器中,就地构造如果容器中不存在具有指定键的元素,则使用提供的参数。

buffer_.emplace(key, std::move(r));

参见这里:https://gcc.godbolt.org/z/zT1PG3d18


话虽这么说,我宁愿建议将

Data&
而不是 r 值传递给
std::reference_wrapper<Data>
,因为
getOrCreateData()
返回
Data&
,这是
addBuffer()
的输入。之间不需要额外的一组转换:

void addBuffer(const std::string& key, Data& r)
//                                     ^^^^^^^
{
  buffer_.emplace(key, std::ref(r));
}

...

int main()
{
  // ....
  auto& r1 = dataManager.getOrCreateData("key1");
  // 
  dataManager.addBuffer("key1", r1);
  //                            ^^^
}
© www.soinside.com 2019 - 2024. All rights reserved.