C++ 映射条目作为参考

C++ map entry as reference

基本上我有一张包含一些条目的地图。我使用自定义构造函数创建条目并删除默认构造函数。在一个条目中,我想更新一个值。我想通过引用条目然后调用 update/set 方法来实现。

我有以下代码:

#include <map>
#include <string>

class CacheEntry
{
    public:
        CacheEntry() = delete;

        CacheEntry(const int value1)
        :   value1(value1)
        {
        }

        void SetValue2(const int value2)
        {
            this->value2 = value2;
        }

    private:
        const int value1;
        int value2;
};

class Cache
{
    public:
        void SetValue2(const std::string& name, const int value2)
        {
            if (entries.count(name) == 0)
            {
                return;
            }
            CacheEntry& entry = entries[name];
            entry.SetValue2(value2);
        }

    private:
        std::map<std::string,CacheEntry> entries;
};

编译时出现如下错误:

In file included from /usr/include/c++/9/bits/stl_map.h:63,
                 from /usr/include/c++/9/map:61,
                 from test.cpp:1:
/usr/include/c++/9/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const std::__cxx11::basic_string<char>; _T2 = CacheEntry]’:
/usr/include/c++/9/tuple:1663:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}; _Args2 = {}; _T1 = const std::__cxx11::basic_string<char>; _T2 = CacheEntry]’
/usr/include/c++/9/ext/new_allocator.h:147:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const std::__cxx11::basic_string<char>, CacheEntry>; _Args = {const std::piecewise_construct_t&, std::tuple<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >]’
/usr/include/c++/9/bits/alloc_traits.h:484:4:   required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const std::__cxx11::basic_string<char>, CacheEntry>; _Args = {const std::piecewise_construct_t&, std::tuple<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::allocator_traits<std::allocator<_Tp1> >::allocator_type = std::allocator<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> > >]’
/usr/include/c++/9/bits/stl_tree.h:614:32:   required from ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_construct_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>, std::tuple<>}; _Key = std::__cxx11::basic_string<char>; _Val = std::pair<const std::__cxx11::basic_string<char>, CacheEntry>; _KeyOfValue = std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >*]’
/usr/include/c++/9/bits/stl_tree.h:631:4:   required from ‘std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>, std::tuple<>}; _Key = std::__cxx11::basic_string<char>; _Val = std::pair<const std::__cxx11::basic_string<char>, CacheEntry>; _KeyOfValue = std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >*]’
/usr/include/c++/9/bits/stl_tree.h:2455:13:   required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>, std::tuple<>}; _Key = std::__cxx11::basic_string<char>; _Val = std::pair<const std::__cxx11::basic_string<char>, CacheEntry>; _KeyOfValue = std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >]’
/usr/include/c++/9/bits/stl_map.h:499:8:   required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::__cxx11::basic_string<char>; _Tp = CacheEntry; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, CacheEntry> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = CacheEntry; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]’
test.cpp:33:36:   required from here
/usr/include/c++/9/tuple:1674:70: error: use of deleted function ‘CacheEntry::CacheEntry()’
 1674 |         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
      |                                                                      ^
test.cpp:7:3: note: declared here
    7 |   CacheEntry() = delete;
      |   ^~~~~~~~~~

为什么编译器会在 CacheEntry& entry = entries[name]; 处创建一个新对象?我希望引用地图中已经存在的对象。

我知道我可以删除 CacheEntry() = delete;,但这不是我想要的。

Why does the compiler create a new object at CacheEntry& entry = entries[name];?

map::operator[] creates a new default-constructed entry if the specified key doesn't exist. Even though you are using map::count() 以确保不会实际创建新条目,operator[] 后面的实现代码仍然需要正确编译。这意味着如果你想使用 operator[]map 的条目必须有一个有效的默认构造函数。

否则,根本不要使用operator[],而是使用map::find(),例如:

void SetValue2(const std::string& name, const int value2)
{
    auto iter = entries.find(name);
    if (iter != entries.end())
        iter->second.SetValue2(value2);
}

I expect a reference to the already existing object in the map.

正确 - 在运行时。但是在编译时,编译器无法知道一个对象是否已经存在。