C++标准是否保证此类间接访问定义良好



下面有三种不同的间接访问样式。我试图了解它们是否都有定义良好的行为,并且可以安全地用于跨平台代码。

#include <cstdint>
#include <iostream>
#include <any>
using namespace std;
#if 1
#define INLINE [[gnu::always_inline]] inline
#else
#define INLINE [[gnu::noinline]]
#endif
INLINE
void mod1(void *p) {
*static_cast<int*>(p) = 10;
}
INLINE
void mod2(uintptr_t p) {
*reinterpret_cast<int*>(p) = 12;
}
INLINE
void mod3(any p) {
*any_cast<int*>(p) = 14;
}
int test1() {
int a1 = 5;
mod1(&a1);
return a1;
}
int test2() {
int a2 = 6;
mod2(reinterpret_cast<uintptr_t>(&a2));
return a2;
}
int test3() {
int a3 = 6;
mod3(&a3);
return a3;
}
int main() {
cout << test1() << "n";
cout << test2() << "n";
cout << test3() << "n";
}

我尝试了内联和noinline,它们都按预期工作,输出10 12 14,所以我认为内联在这里无关紧要。

它们都是按照C++标准定义的行为吗?如有任何帮助,我们将不胜感激:(

[Edit]即使我们考虑基于类型的别名分析

从技术上讲,这两者的行为都不是由标准指定的,因为您使用的是实现定义的属性,这些属性可能会产生任何影响。然而,实际上,这些属性与这里的行为无关。

除此之外:

test1是正确的,并且指定为按预期工作。始终允许将对象指针投射到(可能是cv限定的(void*并通过static_castreinterpret_cast返回到原始类型,并生成原始指针值。然而,这种通过void*相同类型的往返是这种类型转换的唯一序列,通常具有这种保证。

有条件地支持test2。C++标准不能保证存在std::uintptr_t或任何其他类型的对象指针可以转换为的类型。如果std::uintptr_t确实存在,那么行为是用预期输出定义的。整型和对象指针类型之间的映射是由实现定义的,除了通过足够大小的整型返回到原始指针类型的往返强制转换会产生原始指针值。

test3被定义为给出预期的结果,除了它可能(与其他两种情况相反(通过抛出std::bad_alloc而失败。std::any的全部意义在于,您可以将任何类型(例如int*(放入其中,并使用std::any_cast以类型安全的方式再次访问它。它还需要RTTI,有时会故意禁用RTTI(不符合标准(。

最新更新