似乎有两种类型的 C++。实用C++和语言律师C++。在某些情况下,能够将一种类型的位模式解释为一种不同的类型会很有用。浮点技巧就是一个显着的例子。让我们取著名的快速平方根反比(取自Wikipedia,又取自此处):
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); …
Run Code Online (Sandbox Code Playgroud) 我们想在项目的某些部分使用pimpl习语.项目的这些部分也恰好是禁止动态内存分配的部分,这个决定不在我们的控制范围内.
所以我要问的是,在没有动态内存分配的情况下,有没有一种干净又好的方法来实现pimpl习语?
编辑
以下是一些其他限制:嵌入式平台,标准C++ 98,没有外部库,没有模板.
似乎广泛认为类型惩罚通过reinterpret_cast
某种方式被禁止(正确地说:"未定义的行为",即" 本国际标准没有要求的行为 ",并明确指出实现可以在C++中定义行为).使用以下推理不同意我是不正确的,如果是这样,为什么?
如果类型"指向" 的表达式可以使用a 显式转换为"指向" 的类型,则
T1
可以将类型的glvalue表达式强制转换为"引用T2
"类型.结果引用与源glvalue相同的对象,但具有指定的类型.[注意:也就是说,对于左值,参考演员与使用内置和运算符的转换具有相同的效果(同样适用于). - 结束注释]不创建临时,不进行复制,也不调用构造函数或转换函数.T1
T2
reinterpret_cast
reinterpret_cast<T&>(x)
*reinterpret_cast<T*>(&x)
&
*
reinterpret_cast<T&&>(x)
用脚注:
75)这有时被称为类型双关语.
/ 11隐含地,通过示例,带有/ 6到/ 10的限制,但也许最常见的用法(双关语对象)在[expr.reinterpret.cast]/7中解决:
可以将对象指针显式转换为不同类型的对象指针.当
v
对象指针类型的prvalue 转换为对象指针类型"指向cv T
"时,结果为static_cast<cv T*>(static_cast<cv void*>(v))
.[注意:将"指向T1
"的类型的prvalue转换为"指向"的类型T2
(T1 and T2
对象类型和对齐要求的T2
位置不比那些更严格T1
)并返回其原始类型会产生原始指针值. - 结束说明]
显然,目的不能转换为/从指针或引用void
,如:
static_cast
在指针的情况下应该足够了,[expr.static.cast]/13和[conv.ptr]/2 ; 和void …
我正在看这个答案,我想知道是否使用reinterpret_cast将对象转换为第一个成员并使用结果在C++中是安全的.
假设我们有一个A类,一个B类和一个B的实例b:
class A{
public:
int i;
void foo(){}
};
class B{
public:
A a;
};
B b;
Run Code Online (Sandbox Code Playgroud)
问题1:使用这样的ba是否安全:reinterpret_cast<A*>(&b)->foo()
?
注意:在一般情况下,我们假设类及其成员都是标准布局.
我关于reinterpret_cast的可用引用的讲座告诉我这样的用法应该被授权,因为没有别名违规,但是它与许多答案冲突,比如这个.
问题2:使用这样的ba是否安全:static_cast<A*>(static_cast<void*>(&b))->foo()
?
c++ type-conversion undefined-behavior reinterpret-cast c++11
这是一个玩具示例,我认为会调用未定义的行为:
#include <cstdint>
#include <iostream>
#include <vector>
int
main()
{
std::vector<uint16_t> foo = {0, 0x42F6};
std::cout << *reinterpret_cast<float*>(foo.data()) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我很确定取消引用它的结果reinterpret_cast
会违反严格的别名规则.然而:
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
$ g++ -fstrict-aliasing -Wstrict-aliasing -fsanitize=undefined -std=c++14 -o a a.cpp
$ ./a
123
Run Code Online (Sandbox Code Playgroud)
没有来自编译器或UB消毒剂的警告.为什么不?