Я пытаюсь научиться использовать 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);
}
Почему ты не делаешь buffer_.insert({key, r}); так, как делал с keyToData_?
@Юджин, это не работает
@Элджей, нет причины, я просто не заметил, моя вина





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);
// ^^^
}
большое спасибо! это сработало. Кстати, почему существует разница между реализацией вставки и оператором []? оба должны работать одинаково? я не понимал, что нужно, чтобы его можно было конструировать по умолчанию.
@AmanKumar На ваши вопросы есть прямой ответ здесь: вставка vs emplace vs оператор в карте C++
Передавайте
std::reference_wrapper<Data>по значению, а не по ссылке на значение r.