我仍在努力理解严格别名允许和不允许的内容。这个具体的例子是否违反了严格的别名规则?如果不是,为什么?是因为我将新的不同类型放入 char* 缓冲区吗?
template <typename T>
struct Foo
{
struct ControlBlock { unsigned long long numReferences; };
Foo()
{
char* buffer = new char[sizeof(T) + sizeof(ControlBlock)];
// Construct control block
new (buffer) ControlBlock{};
// Construct the T after the control block
this->ptr = buffer + sizeof(ControlBlock);
new (this->ptr) T{};
}
char* ptr;
T* get() {
// Here I cast the char* to T*.
// Is this OK because T* can alias char* or because
// I placement newed a T …Run Code Online (Sandbox Code Playgroud) 我最近一直试图理解严格别名的一个特定方面,我想我已经制作了尽可能小的有趣代码.(对我来说很有趣,就是!)
更新:根据目前为止的答案,很明显我需要澄清这个问题.从某个角度来看,这里的第一个列表是"明显"定义的行为.真正的问题是遵循这个逻辑到自定义分配器和自定义内存池.如果我malloc在开始时有一大块内存,然后编写我自己的my_malloc并且my_free使用那个单个大块,那么UB是不是因为它不使用官方free?
我会坚持使用C,有点随意.我得到的印象是更容易谈论,C标准更清晰一点.
int main() {
uint32_t *p32 = malloc(4);
*p32 = 0;
free(p32);
uint16_t *p16 = malloc(4);
p16[0] = 7;
p16[1] = 7;
free(p16);
}
Run Code Online (Sandbox Code Playgroud)
第二个可能malloc会返回与第一个相同的地址malloc(因为它free介于两者之间).这意味着它正在访问具有两种不同类型的相同内存,这违反了严格的别名.那么上面肯定是未定义的行为(UB)?
(为简单起见,让我们假设malloc总是成功.我可以添加检查返回值malloc,但这会使问题混乱)
如果不是UB,为什么?标准中是否有明确的例外,它说malloc和free(和calloc/ realloc/ ...)被允许"删除"与特定地址相关的类型,允许进一步访问在地址上"压印"一个新类型?
如果malloc/ free是特殊的,那么这是否意味着我不能合法地编写我自己的克隆行为的分配器malloc?我确信有很多项目都有自定义分配器 - 它们都是UB吗?
因此,如果我们决定必须定义这样的自定义分配器行为,则意味着严格别名规则本质上是"不正确的".我会更新它,说只要你不再使用旧类型的指针,就可以通过不同('new')类型的指针写入(不读取).如果确认所有编译器基本上都遵守了这个新规则,那么这个措辞可能会悄然改变.
我得到的印象是,gcc并且clang基本上尊重我的(积极的)重新解释.如果是这样,也许应该相应地编辑标准?关于 …