使用const键擦除set中的元素

Mat*_*zak 7 c++ stl language-lawyer

无序的设置键是只读的,所以为什么在这种情况下我可以擦除元素:

std::unordered_set<std::string> s;
s.emplace("sth");
s.erase("sth");
Run Code Online (Sandbox Code Playgroud)

而在这不是:

std::unordered_set<std::string const> s;
const std::string str("sth");
s.emplace(str);
s.erase(str);
Run Code Online (Sandbox Code Playgroud)

如果设置本身就是const它会有意义但是使用const键我不太明白.这个断言失败了:

static_assert(!is_reference<_Tp>::value && !is_const<_Tp>::value, "");
Run Code Online (Sandbox Code Playgroud)

为什么会写那个断言的人,检查密钥是不是const?

编辑:

实际上,上面的代码编译得很好std::set.因为std::unordered_set,失败直接在实例化.重现的最小例子:

// define a customized hash ... 
int main() { sizeof(std::unordered_set<int const>); }
Run Code Online (Sandbox Code Playgroud)

AEX*_*AEX 0

我认为您缺少的是 std::set 实际上分配了自己的字符串。因此,当您说 s.emplace("sth") 时,它会创建一个新的“sth”字符串,它不会使用您的字符串(它使用它来构造一个新字符串)。为什么这些新分配的字符串是 const ?因为你不应该直接修改它们,否则你会破坏集合。如果直接将“aaa”更改为“zzz”,则集合仍会认为“zzz”是集合中的第一个元素,位于“bbb”之前。

那么为什么会有这个断言呢?因为 std 没有 const 对象的分配器 - 所以当它尝试分配 const 对象时它将失败。VS2017 的错误更加明显:“C++ 标准禁止 const 元素的容器,因为分配器格式不正确。”