Строка ссылки string_view на const становится недействительной

Сегодня я наткнулся на этот простой код.

#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

int main(int argc, char* argv[]) {
  std::unordered_map<std::string, int> m = {
      {"asdf", 123},
      {"dsdfesjfdaslkfjasljlasfjlasjfakdlsfjasklfajsklfjaskljlf", 123},
      {"ldfjaslk}sfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
      {"ldafjaslk}sfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
      {"ldjaksdfjfjaslk}sfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
      {"ldfjaslk}sfdasfdsfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
      {"ldfjaslk}sfjalsksfdasdfdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
      {"ldfjaslk}sfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj", 1},
  };

  std::vector<std::pair<std::string_view, int>> vec;

  for (auto& [s, i] : m) {
    vec.push_back(std::make_pair(s, i));
    std::cout << vec.back().first << std::endl;
  }
}

По сути, вектор создается с помощью элемента карты. Дело в том, что вместо этого он преобразует строку в string_view при вставке в вектор. Я подумал, что это будет нормально, так как мы используем константную ссылку на строку для построения string_view, и строка будет доступна в течение всего срока службы вектора.

Но когда я проверил вывод, он показал, казалось бы, поврежденные данные.

�/�U.�Usfdasdfdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj
�/�U.�Usfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj
@/�U.�Ukdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj
�/�U.�Usfjalskdfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj
@/�U.�Udfjlkdasjfaslkfjaskdljflaskdfjdaslkfjasdlkfjasdlj
.�Usljlasfjlasjfakdlsfjasklfajsklfjaskljlf
asdf

Я предполагаю, что string_view в векторе больше не указывает на правильный элемент. Но почему это произошло? Я предполагал, что unordered_map будет неизменяем во время итерации, поэтому адрес ключевого элемента не изменится.

Ссылка на Godbolt: https://godbolt.org/z/dePdv5

godbolt.org/z/dePdv5
Jaebum 20.12.2020 13:22

Разве std::make_pair не сделает копию строки, а затем vec сохранит ссылку на копию?

spectras 20.12.2020 13:22

Ааа. Поэтому, когда я исправил это на vec.push_back(std::make_pair(std::string_view(s), i));, оно исправилось. Но мне интересно, как бы это не было поведением по умолчанию?

Jaebum 20.12.2020 13:24

Работает намного лучше с emplace_back и без make_pair: Live Demo на coliru ;-)

Scheff's Cat 20.12.2020 13:25
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
4
416
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используя make_pair, вы создаете временный объект типа std::pair<std::string, int>. Я ожидал, что преобразование в std::pair<std::string_view, int> вызовет ошибку, но, похоже, это работает.

В любом случае, std::string_view не принадлежит, поэтому, как только временный объект уничтожается (в конце строки ;), он становится повисшим.

Не стоит заводить новую пару. Попробуйте emplace_back с ключом и значением.

Прохладный. Мне сказали избегать emplace_back, так как это может вызвать неожиданный ctor. Но я думаю, что это единственный случай, когда я нахожу это полезным: P

Jaebum 20.12.2020 13:28

Преобразование существует, потому что std::string в std::string_view является неявным преобразованием. Вы видите, почему люди были «расстроены» этим решением.

Passer By 20.12.2020 13:35

@прохожий серьезно? Думаю, я присоединяюсь к "клубу расстроенных".

JHBonarius 20.12.2020 14:06

Другие вопросы по теме