在C++中,如果释放的内存仍然被一个引用所引用,即使该引用没有被再次使用,这是否是未定义的行为?例如,下面的函数是否调用了未定义的行为?
void foo() {
std::map<std::string, int> mymap;
{
int& val = mymap["eight"];
val = 8;
mymap.erase("eight"); // Oops! val still refers to mymap["eight"]
// val is not used again
}
std::cout << "Entry count: " << mymap.size() << "\n";
}
从[associative.reqmts]p9中,我们看到(强调是我的)。
insert和emplace成员不应影响到容器的迭代器和引用的有效性,而且... ... erase成员只对被擦除元素的迭代器和引用无效。.
这是N4659[basic.stc]p4中的内容。1 再次强调)。
当一个存储区域的持续时间结束时,代表该存储区域任何部分地址的所有指针值都会变成无效指针值(6.9.2)。通过无效指针值进行引导和将无效指针值传递给deallocation函数的行为是未定义的。. 任何其他用途 的无效指针值具有实现定义的行为。
虽然文中特别谈到了指针,但没有理由相信它不适用于引用(好吧,在某种程度上它们可以被认为是指针)。另外,请注意,它说"Any other use
",所以只要在表达式失效后不在表达式中使用指针引用,行为应该是很好定义的。
1 注:看来这段文字是在N4659中添加的,在标准的早期版本中似乎并不存在。
对释放的内存有引用是未定义的行为吗?
标准并没有为 "拥有 "任何类型的值定义任何行为。
mymap.erase("eight"); // Oops! val still refers to mymap["eight"]
以下是标准中关于 erase
:
[associative.reqmts].。擦除成员应使被擦除元素的引用无效......。
请注意,这条规则并没有说如果这些引用存在,行为就没有定义。事实上,如果引用的存在总是意味着未定义的行为,那么描述那些引用无效是相当没有意义的。
至于什么是无效引用的定义......标准似乎有所欠缺。无效指针有定义,但我找不到无效引用的定义。这种缺乏定义的情况可以被认为是标准的一个缺陷。