【问题标题】:string_view to const reference string gets invalidatedstring_view 到 const 引用字符串无效
【发布时间】:2020-12-20 12:14:06
【问题描述】:

我今天遇到了这个简单的代码。

#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 。我认为这没问题,因为我们使用 const 字符串引用来构造 string_view,并且该字符串将在向量的整个生命周期中可用。

但是当我检查输出时,它显示了看似损坏的数据。

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

我猜向量中的 string_view 不再指向正确的元素。但是为什么会这样呢?我假设 unordered_map 在迭代时是不可变的,因此关键元素的地址不会改变。

天箭链接:https://godbolt.org/z/dePdv5

【问题讨论】:

  • 不会std::make_pair 复制字符串,然后 vec 存储对副本的引用吗?
  • 啊。因此,当我将其修复为 vec.push_back(std::make_pair(std::string_view(s), i)); 时,它修复了它。但我想知道这怎么会不是默认行为?
  • 使用emplace_back 和不使用make_pair 时效果更好:Live Demo on coliru ;-)

标签: c++


【解决方案1】:

使用make_pair 可以生成std::pair&lt;std::string, int&gt; 类型的临时对象。我希望转换为 std::pair&lt;std::string_view, int&gt; 会引发错误,但显然它可以工作。

无论如何,std::string_view 是非拥有的,所以一旦临时对象被销毁(在; 行的末尾),它就会变得悬空。

你不应该做一双新的。使用键和值尝试emplace_back

【讨论】:

  • 酷。我被告知要避免使用 emplace_back,因为它可能会调用意外的 ctor。但我想这是我觉得有用的唯一情况:P
  • 转换存在是因为std::stringstd::string_view 是隐式转换。你有点明白为什么人们对这个决定感到“不安”了。
  • @passerby 认真的吗?我想我现在加入了“心烦意乱的俱乐部”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-14
  • 1970-01-01
相关资源
最近更新 更多