[basic.compound]
如果两个对象是指针可互换的,那么它们具有相同的地址
然后注意到
数组对象及其第一个元素不是指针可互换的,即使它们具有相同的地址
使数组对象及其第一个元素非指针可互换的基本原理是什么?更一般地说,区分指针 - 可互换性概念与具有相同地址的概念的理由是什么?在那里某处不存在矛盾吗?
看来,给定这一系列陈述
int a[10];
void* p1 = static_cast<void*>(&a[0]);
void* p2 = static_cast<void*>(&a);
int* i1 = static_cast<int*>(p1);
int* i2 = static_cast<int*>(p2);
Run Code Online (Sandbox Code Playgroud)
p1 == p2
但是,我们已经i1
明确定义并且使用i2
会导致UB.
目前的标准草案(可能是C++ 17)在[basic.compound/4]中说:
[注意:数组对象及其第一个元素不是指针可互换的,即使它们具有相同的地址. - 结束说明]
因此,指向对象的指针不能reinterpret_cast
获得其封闭的数组指针.
现在,有std::launder
,[ptr.launder/1]:
template<class T> [[nodiscard]] constexpr T* launder(T* p) noexcept
;要求:
p
表示内存中字节的地址A. 在其生命周期内且其类型类似于T的对象X位于地址A处.可通过结果到达的所有存储字节都可通过p
(见下文)到达.
和的definion 可达是在[ptr.launder/3] :
备注:只要可以在核心常量表达式中使用其参数的值,就可以在核心常量表达式中使用此函数的调用.如果对象Y位于Y所占用的存储区内,则指向存储的字节可以到达,如果Y是指针可互换的对象,则指向对象Y,或者如果Y是数组元素,则指向立即封闭的数组对象.如果T是函数类型或cv void,则程序格式错误.
现在,乍一看,似乎std::launder
可以用来做上述转换,因为我强调的部分.
但.如果p
指向数组的对象,则根据此定义可以访问数组的字节(即使p
不是指针可互换为数组指针),就像清洗的结果一样.因此,该定义似乎没有说明这个问题.
那么,可以std::launder
用来将对象指针转换为其封闭的数组指针吗?
考虑以下代码:
struct A {
virtual A& operator+=(const A& other) noexcept = 0;
};
void foo_inner(int *p) noexcept { *p += *p; }
void foo_virtual_inner(A *p) noexcept { *p += *p; }
void foo(int *p) noexcept
{
return foo_inner(p);
}
struct Aint : public A {
int i;
A& operator+=(const A& other) noexcept override final
{
// No devirtualization of foo_virtual with:
i += dynamic_cast<const Aint&>(other).i;
// ... nor with:
// i += reinterpret_cast<const Aint&>(other).i;
return *this;
}
};
void foo_virtual(Aint …
Run Code Online (Sandbox Code Playgroud) c++ gcc virtual-functions compiler-optimization devirtualization
编辑:原始的单词选择令人困惑.术语"象征性"比原始术语("神秘")要好得多.
在关于我以前的C++问题的讨论中,我被告知指针是
这并没有健全的权利!如果没有任何符号,并且指针是其表示,那么我可以执行以下操作.我可以吗?
#include <stdio.h>
#include <string.h>
int main() {
int a[1] = { 0 }, *pa1 = &a[0] + 1, b = 1, *pb = &b;
if (memcmp (&pa1, &pb, sizeof pa1) == 0) {
printf ("pa1 == pb\n");
*pa1 = 2;
}
else {
printf ("pa1 != pb\n");
pa1 = &a[0]; // ensure well defined behaviour in printf
}
printf ("b = %d *pa1 = %d\n", …
Run Code Online (Sandbox Code Playgroud)