std::清洗和严格的混叠规则
std::launder and strict aliasing rule
请考虑以下代码:
void f(char * ptr)
{
auto int_ptr = reinterpret_cast<int*>(ptr); // <---- line of interest
// use int_ptr ...
}
void example_1()
{
int i = 10;
f(reinterpret_cast<char*>(&i));
}
void example_2()
{
alignas(alignof(int)) char storage[sizeof(int)];
new (&storage) int;
f(storage);
}
来自example_1
电话的兴趣线:
Q1:在调用端,char
指针正在为整数指针设置别名。这是有效的。但是,将其投射回int
是否也有效?我们知道int
在其生命周期内,但请考虑该函数是在另一个翻译单元中定义的(未启用链接时间优化(,并且上下文未知。然后编译器看到的只是:一个int
指针想要为一个char
指针设置别名,这违反了严格的别名规则。那么允许吗?
Q2:考虑到这是不允许的。我们在 17 C++获得了std::launder
。它是一种指针优化屏障,主要用于访问一个对象,该对象被new
放置在其他类型的对象的存储中,或者当涉及const
成员时。我们可以使用它来给编译器一个提示并防止未定义的行为吗?
来自example_2电话的兴趣线:
Q3:这里应该需要std::launder
,因为这是 Q2 中描述std::launder
用例,对吧?
auto int_ptr = std::launder(reinterpret_cast<int*>(ptr));
但再次考虑f
在另一个翻译单元中定义。编译器如何知道我们的放置new
,这发生在调用端?编译器(只看到函数f
(如何区分example_1
和example_2
?或者以上所有只是假设,因为严格的混叠规则只会排除所有内容(记住,char*
int*
不允许(,编译器可以做它想做的事?
后续问题:
Q4:如果上述所有代码由于混叠规则而出错,请考虑将函数f
更改为采用 void 指针:
void f(void* ptr)
{
auto int_ptr = reinterpret_cast<int*>(ptr);
// use int_ptr ...
}
然后我们没有混叠问题,但仍然存在std::launder
的情况example_2
.我们是否更改了调用方并将我们的example_2
函数重写为:
void example_2()
{
alignas(alignof(int)) char storage[sizeof(int)];
new (&storage) int;
f(std::launder(storage));
}
还是功能f
std::launder
就足够了?
严格的混叠规则是对实际用于访问对象的 glvalue 类型的限制。对于该规则而言,所有重要的是 a( 对象的实际类型,以及 b( 用于访问的 glvalue 的类型。
指针经过的中间强制转换是无关紧要的,只要它们保留指针值即可。(这是双向的;再多聪明的强制转换或洗钱也无法治愈严格的混叠违规。
只要ptr
实际指向类型int
的对象,f
就是有效的,假设它通过int_ptr
访问该对象而不进行进一步的强制转换。
example_1
在写入时有效;reinterpret_cast
不会更改指针值。
example_2
是无效的,因为它f
提供了一个指针,该指针实际上并不指向int
对象(它指向storage
数组的生命周期外第一个元素(。请参阅放置 new 的返回值与其操作数的强制转换值之间是否存在(语义(差异?
你不需要在函数 f(( 中 std::launder。作为尽可能通用的函数 f(( 可以与任何指针一起使用:脏(需要洗衣服(或不脏。它仅在呼叫端知道,因此您必须使用如下所示的内容:
void example_2()
{
alignas(alignof(int)) char storage[sizeof(int)];
new (&storage) int; // char[] has gone, now int there
f(std::launder(reinterpret_cast<int*>(storage))); // assiming f(void* p)
}
而 f(( 本身是另一回事。正如你提到的,假设 f(( 被放置在一个共享库中,所以根本没有任何上下文假设。
- 此代码是否违反一个定义规则
- 生成文件不对文件使用隐式规则
- 变量可能尚未初始化[MIRA 2012规则9.1,强制性]
- 静态结构和一个定义规则
- 尽管遵循了规则,内存泄漏在哪里
- 这是关于成员访问规则的正确摘要吗
- uint_not_usable_without_attribute在业力规则中使用数字生成器时静态断言失败
- 增强精神解析器规则以检测语句中的特殊结尾
- 制作文件:没有规则来制定目标:如何设置正确的规则?
- 为什么此指针值不能转换为整数的规则是什么?
- 传递通用函数,用于梯形规则的数值积分
- C++内存模型中的确切规则阻止在获取操作之前重新排序
- 模板如何影响C++中隐式声明的规则?
- antlr 规则上下文是否可以独立于目标
- Bison/flex 在识别规则后等待输入
- 生成文件中隐式规则中的 -c 标志出错
- 单链接列表实现,规则为 3
- 指针算术规则中的"possibly-hypothetical"是什么意思?
- 假设声明中某些上下文中需要的名称查找规则是什么
- std::清洗和严格的混叠规则