C++ 多个std::map.insert();s使用相同的std::对引用,但使用新值会导致映射值不正确。为什么以及如何修复?

C++ 多个std::map.insert();s使用相同的std::对引用,但使用新值会导致映射值不正确。为什么以及如何修复?,c++,reference,c++17,stdmap,std-pair,C++,Reference,C++17,Stdmap,Std Pair,多个std::map.insert()使用相同的std::pair,但使用新值会导致不正确的映射值。如何在不创建此行为的情况下使用单个结构和引用 #include <iostream> // c++17 gcc 8.3.0-6 debian #include <map> #include <tuple> using std::endl, std::cout, std::cerr; struct Struct1 { int s1_int

多个std::map.insert()使用相同的std::pair,但使用新值会导致不正确的映射值。如何在不创建此行为的情况下使用单个结构和引用

#include <iostream>  // c++17 gcc 8.3.0-6 debian
#include <map>
#include <tuple>
using std::endl, std::cout, std::cerr;
struct Struct1 {
    int         s1_int1 {}, s1_int2 {};
    std::string s1_str1 {};
    struct Key {
        decltype (s1_int1) & key_part1;
        decltype (s1_int2) & key_part2;
    } key   { s1_int1, s1_int2 };
    struct Value {
        decltype (s1_str1) & value_part1;
    } value { s1_str1 };
    struct Compare {
        bool operator()( Key const & lhs, Key const & rhs) const {
            return std::tie( lhs.key_part1, lhs.key_part2 ) < std::tie( rhs.key_part1, rhs.key_part2 );
        }
    };
    void print (std::string message) const {
        cerr<<message<<">> s1_int1:"<< s1_int1<<", s1_int2:"<<s1_int2<<", s1_str1:"<<s1_str1<<endl;
    }
};
void r_print( std::pair<Struct1::Key,Struct1::Value> const & pair, bool is_inserted ) {
    cerr<<"is_inserted:"<<is_inserted<<", key.key_part1:"<<pair.first.key_part1<<", key.key_part2:"<<pair.first.key_part2<<", value.s1_str1:"<<pair.second.value_part1<<endl;
};
int main()
{
    std::map<Struct1::Key, Struct1::Value, Struct1::Compare > my_map {};
    Struct1 map_value1 {11,12,"s13"}, map_value2 = {21,22,"s23"};
    map_value1.print("map_value :12");
    auto const r1 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r1.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value2.print("map_value2:22");
    auto const r2 = my_map.insert( {map_value2.key,map_value2.value} );
    r_print( *r2.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value1.s1_int1 = 31; map_value1.s1_int2 = 32; map_value1.s1_str1 = "s33";
    map_value1.print("map_value :31");
    auto const r3 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r3.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;
    cout << "###" << endl;
    return 0;
}
归结起来就是:

struct S {
  int m;
  int& r = m;
};

S s1{42};
S s2{s1};
s1.m = 84;
std::cout << s2.r;  // prints 84
结构{
int m;
int&r=m;
};
s1{42};
s2{s1};
s1.m=84;

std::cout结果表明std::map需要值类型。我提到了价值观。为了修复它,我只需将引用与引用值交换。现在,键和值不再是引用。对于确切的问题可能有更好的解释,但我真的不知道

#include <iostream>  // c++17 gcc 8.3.0-6 debian
#include <map>
#include <tuple>
using std::endl, std::cout, std::cerr;
struct Struct1 {
    struct Key {
        int key_part1;
        int key_part2;
    } key;
    struct Value {
        std::string value_part1;
    } value;
    int & s1_int1 {key.key_part1}, & s1_int2 {key.key_part2};
    std::string & s1_str1 {value.value_part1};
    struct Compare {
        bool operator()( Key const & lhs, Key const & rhs) const {
            return std::tie( lhs.key_part1, lhs.key_part2 ) < std::tie( rhs.key_part1, rhs.key_part2 );
        }
    };
    void print (std::string message) const {
        cerr<<message<<">> s1_int1:"<< s1_int1<<", s1_int2:"<<s1_int2<<", s1_str1:"<<s1_str1<<endl;
    }
};
void r_print( std::pair<Struct1::Key,Struct1::Value> const & pair, bool is_inserted ) {
    cerr<<"is_inserted:"<<is_inserted<<", key.key_part1:"<<pair.first.key_part1<<", key.key_part2:"<<pair.first.key_part2<<", value.s1_str1:"<<pair.second.value_part1<<endl;
};
int main()
{
    std::map<Struct1::Key, Struct1::Value, Struct1::Compare > my_map {};
    Struct1 map_value1 {11,12,"s13"} , map_value2 {21,22,"s23"};
    map_value1.print("map_value :12");
    auto const r1 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r1.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value2.print("map_value2:22");
    auto const r2 = my_map.insert( {map_value2.key,map_value2.value} );
    r_print( *r2.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value1.s1_int1 = 31; map_value1.s1_int2 = 32; map_value1.s1_str1 = "s33";
    map_value1.print("map_value :31");
    auto const r3 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r3.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;
    cout << "###" << endl;
    return 0;
}


伊戈尔,谢谢你的详细分析。我确实需要引用,因为正如我在这里所指出的:>>一些人可能建议的一个简单答案是不要使用Struct1::Key中的引用,但是我正在尝试让顶级数据成员在struct中易于访问,也可以轻松创建插入std::map.Igor的对,是的,引用是指针,指针是int(粗略地说),但请理解示例代码“int”可能是数据库键中的“长字符串”,然后指针会更小。我还希望同步这些值,以允许对数据库行进行双重访问,因此ref似乎非常适合这样做。原因是我希望代码能被ORM或Sqlite使用,他们似乎喜欢简单的记录,比如structs.Igor,谢谢你的例子。我原以为地图会复制,裁判不会破坏地图。我错了。我真想知道为什么不能,或者地图怎么会给我一个编译时错误,甚至是一个运行时错误(是的,后者会很慢)。@GrantRostig:唯一的错误是你改变了一个键(或者更确切地说是它引用的东西),从而影响了它的比较顺序。检查这一点相当昂贵(一般来说是不可能的),所以事实并非如此。您似乎在说,您希望映射以某种方式生成键的深度副本,并在内部存储实际值,而不仅仅是引用。同时,您担心键值可能很大且复制成本高,并引入引用以避免数据重复(同时,您也认为地图应该以某种方式自动复制相同的数据)。我不明白你怎么能调和这两个相互矛盾的观点。我必须承认,我仍然不确定你为什么坚持在这里使用参考资料,你认为它们能帮助实现什么具体目标。
#include <iostream>  // c++17 gcc 8.3.0-6 debian
#include <map>
#include <tuple>
using std::endl, std::cout, std::cerr;
struct Struct1 {
    struct Key {
        int key_part1;
        int key_part2;
    } key;
    struct Value {
        std::string value_part1;
    } value;
    int & s1_int1 {key.key_part1}, & s1_int2 {key.key_part2};
    std::string & s1_str1 {value.value_part1};
    struct Compare {
        bool operator()( Key const & lhs, Key const & rhs) const {
            return std::tie( lhs.key_part1, lhs.key_part2 ) < std::tie( rhs.key_part1, rhs.key_part2 );
        }
    };
    void print (std::string message) const {
        cerr<<message<<">> s1_int1:"<< s1_int1<<", s1_int2:"<<s1_int2<<", s1_str1:"<<s1_str1<<endl;
    }
};
void r_print( std::pair<Struct1::Key,Struct1::Value> const & pair, bool is_inserted ) {
    cerr<<"is_inserted:"<<is_inserted<<", key.key_part1:"<<pair.first.key_part1<<", key.key_part2:"<<pair.first.key_part2<<", value.s1_str1:"<<pair.second.value_part1<<endl;
};
int main()
{
    std::map<Struct1::Key, Struct1::Value, Struct1::Compare > my_map {};
    Struct1 map_value1 {11,12,"s13"} , map_value2 {21,22,"s23"};
    map_value1.print("map_value :12");
    auto const r1 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r1.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value2.print("map_value2:22");
    auto const r2 = my_map.insert( {map_value2.key,map_value2.value} );
    r_print( *r2.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;

    map_value1.s1_int1 = 31; map_value1.s1_int2 = 32; map_value1.s1_str1 = "s33";
    map_value1.print("map_value :31");
    auto const r3 = my_map.insert( {map_value1.key,map_value1.value} );
    r_print( *r3.first, r1.second );
    for (auto & [key,value]:my_map )
        cerr<< "key.key_part1:"<<key.key_part1<<", key.key_part2:"<<key.key_part2<<", value.s1_str1:"<<value.value_part1<<endl;
    cout << "###" << endl;
    return 0;
}

map_value :12>> s1_int1:11, s1_int2:12, s1_str1:s13
is_inserted:1, key.key_part1:11, key.key_part2:12, value.s1_str1:s13
key.key_part1:11, key.key_part2:12, value.s1_str1:s13
map_value2:22>> s1_int1:21, s1_int2:22, s1_str1:s23
is_inserted:1, key.key_part1:21, key.key_part2:22, value.s1_str1:s23
key.key_part1:11, key.key_part2:12, value.s1_str1:s13
key.key_part1:21, key.key_part2:22, value.s1_str1:s23
map_value :31>> s1_int1:31, s1_int2:32, s1_str1:s33
is_inserted:1, key.key_part1:31, key.key_part2:32, value.s1_str1:s33
key.key_part1:11, key.key_part2:12, value.s1_str1:s13
key.key_part1:21, key.key_part2:22, value.s1_str1:s23
key.key_part1:31, key.key_part2:32, value.s1_str1:s33
###