如何解决c ++:具有一对string_viewes的无序映射
这是我的代码片段:
struct PairHasher {
size_t operator()(const std::pair<std::string_view,std::string_view>& stop_stop) const {
return hasher(stop_stop.first) + 37*hasher(stop_stop.second);
}
std::hash<std::string_view> hasher;
};
BOOST_FIXTURE_TEST_CASE(unordered_map_string_view_pair_must_be_ok,TestCaseStartStopMessager)
{
const std::vector<std::string> from_stops = {"from_0","from_1","from_2"};
const std::vector<std::string> to_stops = {"to_0","to_1","to_2"};
std::unordered_map<std::pair<std::string_view,std::string_view>,std::int32_t,TransportCatalogue::PairHasher> distance_between_stops;
for ( std::size_t idx = 0; idx < from_stops.size(); ++idx) {
std::cout << from_stops[idx] << " : " << to_stops[idx] << std::endl;
distance_between_stops[std::pair(from_stops[idx],to_stops[idx])] = idx;
}
std::cout << "MAP CONTENT :" << std::endl;
for (auto const& x : distance_between_stops)
{
std::cout << x.first.first << " : " << x.first.second << std::endl;
}
}
我希望在容器内看到 3 对,但输出中只有 1 对:
MAP CONTENT :
from_2 : to_2
那么,哪里又丢了两对?我做错了什么?
解决方法
将我的评论移至答案。
这太狡猾了。我注意到在 Compiler Explorer 中发生了变化:
distance_between_stops[std::pair(from_stops[idx],to_stops[idx])] = idx;
到
distance_between_stops[std::pair(std::string_view{from_stops[idx]},std::string_view{to_stops[idx]})] = idx;
修复了错误。这暗示问题在于某些隐式 string
-> string_view
转换。确实如此,但它隐藏在额外的一层之后。
std::pair(from_stops[idx],to_stops[idx])
创建一个 std::pair<std::string,std::string>
,但 distance_between_stops
需要一个 std::pair<std::string_view,std::string_view>
。当我们向映射中插入值时,这种转换会通过重载 #5 here:
template <class U1,class U2>
constexpr pair(pair<U1,U2>&& p);
- 用
first
初始化std::forward<U1>(p.first)
,用std::forward<U2>(p.second)
初始化第二个。
- 当且仅当
std::is_constructible_v<first_type,U1&&>
和std::is_constructible_v<second_type,U2&&>
都是true
时,此构造函数参与重载决议。 - 此构造函数为
explicit
当且仅当std::is_convertible_v<U1&&,first_type>
为false
或std::is_convertible_v<U2&&,second_type>
为false
。
(作为参考,std::is_constructible_v<std::string_view,std::string&&>
和 std::is_convertible_v<std::string&&,std::string_view>
都是 true
,所以我们知道这个重载是可行且隐含的。)
看到问题了吗?当我们使用映射的 operator[]
时,它必须进行隐式转换以创建具有正确类型的键。这种隐式转换构造了一对 string_view
,它们从本地 string
对查看 临时 内存,而不是 vector
中的底层字符串。换句话说,它在概念上类似于:
std::string_view foo(const std::string& s) {
std::string temp = s + " foo";
return temp;
}
int main() {
std::string_view sv = foo("hello");
std::cout << sv << "\n";
}
Clang 为这个小例子发出警告,但没有 OP 的完整例子,这很不幸:
warning: address of stack memory associated with local variable 'temp' returned [-Wreturn-stack-address]
return temp;
^~~~
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。