0

I have a simple map with const char* key and bool value, and I have preadded keys, but when I try to modify a value with a string, it creates a new entry, not edits an existing entry, and I have both with same key name.

map<const char*, bool> test=
    {
        {"Test", false},
        {"test2", false}
    };

string s = "Test";
test[s.c_str()] = true;

Gives me map test with

{"Test", false},
{"test2", false},
{"Test", false;}

map

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
elllkere
  • 39
  • 2
  • Yes, that is correct. `0x005331B0`, `0x005331B8`, and `0x00BBF9C4` are all separate keys. – Eljay Jan 07 '23 at 20:20
  • The key isn't the string, but the value of the pointer variable (like: 0x203348). – jxh Jan 07 '23 at 20:20
  • You're mapping a memory address key to a bool; not a string to a bool. The address from the literal `"Test"` is not the same as the address from `s.c_str()`. The question to ask yourself is why your map isn't `std::map`. – WhozCraig Jan 07 '23 at 20:20
  • _"i try to modify key"_ - You are trying to modify the _value_, not the _key_. – Ted Lyngmo Jan 07 '23 at 20:23
  • This is pretty much a dup of: https://stackoverflow.com/a/25123055/315052 – jxh Jan 07 '23 at 20:25
  • 1
    I'm 110% sure that you really want `map`. – Paul Sanders Jan 07 '23 at 23:32

1 Answers1

3

If you really want have C strings as keys you need to provide a user defined comparator since otherwise the map will compare the actual pointer values, not the C strings they point at.

Example:

#include <cstring>
#include <iostream>
#include <map>
#include <string>

// a comparator class for C strings
struct cstring_less {
    bool operator()(const char* lhs, const char* rhs) const {
        return std::strcmp(lhs, rhs) < 0;
    }
};

int main() {
    // supply the comparator as the third template parameter:
    std::map<const char*, bool, cstring_less> test = {
        {"Test", false},
        {"test2", false}
    };
    
    std::string s = "Test";
    test[s.c_str()] = true;

    for(auto&[k,v] : test) {
        std::cout << k << ' ' << v << '\n';
    }
}

I really suggest that you use std::string as Key though.

The current map can't be used if any of the C strings (that are not string literals) you store pointers to have gone out of scope. The pointers you store are then "dangling" and dereferencing them would make the program have undefined behavior.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Sound advice at the end of this, to be sure. If the order of insertions were opposite (`s.c_str()` were keyed *first*) and `s` had deeper automatic scope (say, from a function or a loop body), the map would be left with a dangling pointer as a key. – WhozCraig Jan 07 '23 at 20:34
  • @WhozCraig Indeed. That'd be terrible for sure! – Ted Lyngmo Jan 07 '23 at 20:34