Ami*_*rsh 7 c++ placement-new language-lawyer c++20
这是在具有参考字段的类上放置 new的答案的后续。
调用std::vector<A>::data()上型A具有参考或常量字段,将指针返回到对象可通过原始向量通过放置新的,这将导致一个的const或参考场来改变原始对象将被替换,而仍然被另一指针管理,通过调用返回data()。
例如:
struct A {
const int i = 0;
};
int main() {
std::vector<A> vec = {{1}, {2}};
auto ptr = vec.data();
std::cout << ptr[1].i << std::endl; // 2
vec.pop_back();
vec.push_back({3}); // placement new, inside
std::cout << ptr[1].i << std::endl; // 3
}
Run Code Online (Sandbox Code Playgroud)
C++17 试图通过引入来解决这些问题,std::launder但后来同意虽然std::launder可以解决其他问题,但它并没有真正解决上述用例的问题,如NB US042 中所述。
一些问题 - 对于C++20 之前的C++ 版本:
由于NB US042被接受为 C++20 规范的更改,但未标记为 DR - 是否仅根据规范建议避免在具有引用或常量字段std::vector<A>::data()的类型上使用,A如上例子?
或者,规范的措辞std::vector<>::data()涵盖了这一点,使其合法并将可实现性问题留给库实现者?
如果是后者,图书馆可以做些什么来使其合法?
如果它真的不能做任何有用的事情来使它合法,它是 C++20 之前的 UB吗?
如果它是 C++20 之前的 UB,为什么这个变化不被认为是 DR 的候选者,与p0593r6相同?无论如何,编译器很可能会做正确的事情,为什么不追溯要求呢?
这段代码是否有效取决于实现是否具有严格的指针安全性,这是 C++20 中消除的概念。
简单地说,在调用 后,指针ptr对于 [ ptr, ) 范围内的算术有效。ptr+2data()
在调用 后pop_back(),任何保存的指向索引 1 的指针肯定是无效的,因为迭代器失效规则std::vector<T>::pop_back()
效果:在擦除点或擦除点之后使迭代器和引用无效。
调用 后pop_back(),先前获得的指针ptr对于其原始范围内的算术不再有效(使用它进行计算ptr+1不再产生“安全派生”的指针值)。
调用后push_back(),算术使用的严格安全性ptr不会恢复。然而,在具有“宽松的指针安全性”的实现上,仍然允许使用原始的索引ptr,该索引尚未被失效pop_back()(仅减少了可达范围)。也就是说,表达式ptr+1和ptr[1]涉及有效但不安全派生的指针值。
新的调用data()返回一个指针值,该值与原始值相等,但与旧保存的指针不同,它可以用于安全地导出向量当前长度的值。同样,具有宽松指针有效性的实现并不关心。
对 C++20 对具有 const 成员的对象的生命周期所做的更改在这里不起作用,因为使用现有指针来引用替换对象不仅[basic.life]被pop_back.
| 归档时间: |
|
| 查看次数: |
320 次 |
| 最近记录: |