【发布时间】:2021-01-27 05:11:50
【问题描述】:
考虑以下代码:
std::map<int, int> m;
int &ref = m[0];
int *ptr = &m[0];
m.insert({1,2});
std::cout << ref; // #1
std::cout << *ptr; // #2
对于像std::map 这样的关联容器,标准的says:
insert 和 emplace 成员不得影响迭代器的有效性和对容器的引用,...
这意味着#1 绝对可以。但是,我不太确定#2。
这个问题是 asked 并在十多年前回答。
接受的答案是 #2 在技术上是不允许的,但在实践中会起作用。
一致的答案(赞成票的数量是接受的答案的两倍多)说#2 没问题,只是说上面的标准引用暗示指针也没有失效。
这个问题也至少有六个相对较新的重复,其中大多数都有答案,并且都说#2 可以,通常引用上面相同的标准文本。
我不认为这是正确的。据我了解,引用是 not 指针,一个不能替代另一个,无论它们是否相互实现。作为比较,以下是标准says 在重新散列时关于无序关联容器中元素的引用的有效性:
重新散列使迭代器无效,...,但不会使指针或对元素的引用无效。
这明确保证了指针的有效性,暗示引用的有效性并不自动暗示它。
那么语言是否说#2 可以? #1的有效性是否暗示了它?
【问题讨论】:
-
这个问题可以改写:当左值引用(其固有属性是底层对象的地址可以指向一个左值)时,是否允许对象更改它们的地址应该保持有效。我非常有信心这个问题的答案是否定的,但显然你想要一个更复杂的答案。另请记住,该标准并非没有错误,并且确实会发生歧义和疏忽。
-
这是一个措辞缺陷。指针没问题。这就是标准的意图,否则我会吃掉我的帽子。继续前进,这里没什么可看的。
-
另请注意,您引用的问题主要讨论指针与参考,而您关心的是参考与指针
-
@SebastianHoffmann 如果有助于回答问题,我可以以任何等效的方式重新表述问题。对不起,我不明白你的第二条评论。您的意思是在其中使用 iterator 吗?
-
您希望
int *pref = &ref;有效还是无效?m[0]返回一个引用,因此获取它的地址(存储在ptr中)相当于同样的事情。
标签: c++ pointers reference language-lawyer