0

When using std::string_view as a key in a map, are we responsible for making sure the underlying string/char we used to create the std::string_view is still alive. Reason why I ask this, is because I am seeing very strange behaviour with my map. After I emplace my second key, the first key gets overwritten by the second key.

std::unordered_map<std::string_view, std::unique_ptr<CustomClass> > m_map;

emplace_in_map(std::string_view str, std::unique_ptr<CustomClass> ccc){
   m_map.emplace(str, std::move(ccc));
}
 wrapper(std::string str) {
     // create ccc
    emplace_in_map(str, ccc);
  }

main(){
     wrapper("test1");
     wrapper("test2"); // after this test1 key get overwritten by test2
     
 }

After the second call I have a map with two keys that are both equal to test2

user438383
  • 5,716
  • 8
  • 28
  • 43
ATK
  • 1,296
  • 10
  • 26
  • 4
    If course yes, you are responsible. **Notes It is the programmer's responsibility to ensure that std::string_view does not outlive the pointed-to character array** – 273K May 19 '22 at 15:58
  • 1
    Yes, you need to keep the string alive. String literals stay alive during the entire program execution, but `string_view` binds not to a literal but the `string` parameter, which dies shortly. – HolyBlackCat May 19 '22 at 15:58
  • 1
    Maybe see this: [Safe way to use string_view as key in unordered map](https://stackoverflow.com/questions/69678864/safe-way-to-use-string-view-as-key-in-unordered-map). It seems a highly similar question. – WhozCraig May 19 '22 at 15:59
  • 1
    Ask yourself - what is the lifetime of `std::string str`? That function parameter is **every** string you're trying to _view_ later. – Drew Dormann May 19 '22 at 16:01
  • Btw, STL containers aren't great at handling `string_view`. For example, `std::set` would not support `find(std::string_view)`. One of the ways around this is using Abseil maps/sets, because they feature [heterogeneous lookup](https://abseil.io/docs/cpp/guides/container#heterogeneous-lookup). – Jacob Dlougach May 20 '22 at 16:40

1 Answers1

2

If you deal with string literals, this will work

template <size_t N>
wrapper(const char (&str)[N]) {
  // create ccc
  emplace_in_map(str, ccc);
}

In other cases Notes

It is the programmer's responsibility to ensure that std::string_view does not outlive the pointed-to character array

273K
  • 29,503
  • 10
  • 41
  • 64
  • 1
    `wrapper(std::string_view str)` would also work. Assuming all these functions were given return types. – Drew Dormann May 19 '22 at 16:15
  • @DrewDormann Yes, it will work in this tiny example, unless OP attempts using `wrapper` with pointers `const char*` to temp arrays or local arrays `char[N]`. – 273K May 19 '22 at 16:20
  • `const char*(&str)[N]` is a (reference to) an array of pointers. You can't initialize that array with a string literal. I think you meant `const char (&str)[N]` for a single string literal instead. Or, you could just use `const char* str` instead. – Remy Lebeau May 19 '22 at 16:29
  • @RemyLebeau Thank you for finding the typo! I would not like using `const char* str` for avoiding issues while calling `wrapper` with local or temp char arrays. – 273K May 19 '22 at 16:31
  • 1
    I don't like the idea of using an array reference as a heuristic to reject non-static strings. You could create a local array that goes of scope, and you could have a pointer to a static string. – HolyBlackCat May 19 '22 at 16:33
  • @HolyBlackCat Of course it does not cover such cases, but prevents from at least a couple other "bad" cases. As I know there is no standard or a portable way of detecting string literals. – 273K May 19 '22 at 16:38