什么是引用/指针失效?

5

我在标准中找不到指针/引用无效化的定义。我提出这个问题是因为我刚刚发现C++11禁止使用字符串的写时复制(COW)。据我所知,如果使用了COW,则在以下命令后p仍将是一个有效的指针,而r将是一个有效的引用:

std::string s("abc");
std::string s2(s);
char * p = &(s2[0]);
char & r = s2[0];
s2[1] = "B";

他们不再指向s2的第一个字符,而仅指向s的第一个字符。
在C++11标准中,非常量std::basic_string::operator[]不能使字符串元素的指针/引用(以及迭代器)失效。
哪些规则说明如果实现了COW,上述示例将使pr失效?

1
那应该是s2[1] = 'B';(一个字符而不是字符串字面量)吗?你现在的代码无法编译。 - Kevin
标准只是说“可能会失效”。 - xskxzr
2个回答

6
标准中没有“invalidation”的定义,因为这个术语是从英语中继承而来的。它在英语中的意思就是:一个失效的引用/指针不再有效。它不能被使用。
然而,在某些地方明确注明了这个约束条件。例如,当将指针lvalue转换为rvalue(在表达式求值期间发生)时:
[conv.lval/2] 否则,如果glvalue所引用的对象包含无效指针值(3.7.4.2, 3.7.4.3),行为是实现定义的。
我现在找不到引用的措辞,但无论如何,不能使用对于不存在的东西的引用,这是不言自明的。

在我的例子中,所提到的字符仍然存在。但我可以理解你的观点。如果s被销毁,那么即使它们与s没有任何关系,根据定义,pr也将被真正地失效。 - Daniel Langr
3
你说它存在,但实现不能保证它。这就是无效化的意思。C++中的任何其他“可能,也可能不可能”的情况都是一样的。建议您按照合同编码,而不是根据机会。可以同意,在某些情况下,你确实可以非常确定一个无效对象实际上仍然存在。然而,这些情况通常都是人为制造的,并不能指导一般情况。 - Lightness Races in Orbit
[conv.lval] 表示 https://timsong-cpp.github.io/cppwp/n4659/basic.compound#def:invalid_pointer_value,是准确的定义,而不是“从英语继承而来的术语”。 - Language Lawyer

0

例如:

std::string * p_s(new ::std::string("abc"));
std::string s2(*p_s); // shares buffer with p_s
char const & ch1(static_cast<::std::string const &>(*p_s)[0]);
char const & ch2(static_cast<::std::string const &>(s2)[0]); // same as ch1
// CoW, ch2 becomes invalid, but is backed by p_s buffer
char & ch(static_cast<::std::string &>(s2)[0]); // backed by new buffer
// both ch1 and ch2 become invalid
delete p_s;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接