新版位如何工作
How does placement new work?
我写了以下内容,认为它应该在运行时出现段错误。但是它没有,它运行良好,我不明白为什么。
#include <cstdlib>
#include <cstdio>
#include <new>
struct MyStruct
{
double *a;
MyStruct()
: a(NULL)
{ printf("Default constructorn"); }
MyStruct( double *b )
: a(b)
{}
MyStruct( const MyStruct& other )
{
printf("Copy-constructorn");
if ( a != NULL && *a != 3.14 )
a = other.a;
}
};
int main()
{
double num = 3.14;
MyStruct obj( &num );
void *ptr = ::operator new( sizeof(MyStruct) );
new (ptr) MyStruct(obj);
delete (MyStruct*) ptr; // Calls ~MyStruct
}
输出为:
Copy-constructor
当我编写void *ptr = ::operator new( sizeof(MyStruct) );
时,我知道这只分配内存,不应该调用默认构造函数。而且似乎不是:很好。
当我写new (ptr) MyStruct(obj);
时,如果它像我想象的那样工作,我希望它会有段错误。我认为这相当于( (MyStruct*) ptr )->MyStruct(obj)
.如果是这样,行if ( a != NULL && *a != 3.14 )
应到达 *a != 3.14
和段错误,因为尚未初始化a
。
我的问题是a
似乎没有初始化(因为没有输出"默认构造函数"),但前一个仍然没有段错误。我错过了什么?
这是生成的汇编代码(我不知道如何阅读):
.file "placement_new.cpp"
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LCPI0_0:
.quad 4614253070214989087 # double 3.1400000000000001
.text
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
push rbp
.Ltmp2:
.cfi_def_cfa_offset 16
.Ltmp3:
.cfi_offset rbp, -16
mov rbp, rsp
.Ltmp4:
.cfi_def_cfa_register rbp
sub rsp, 48
lea rdi, qword ptr [rbp - 24]
lea rsi, qword ptr [rbp - 16]
movsd xmm0, qword ptr [.LCPI0_0]
mov dword ptr [rbp - 4], 0
movsd qword ptr [rbp - 16], xmm0
call _ZN8MyStructC2EPd
movabs rdi, 8
call _Znwm
mov qword ptr [rbp - 32], rax
mov rax, qword ptr [rbp - 32]
cmp rax, 0
mov qword ptr [rbp - 40], rax # 8-byte Spill
je .LBB0_2
# BB#1:
lea rsi, qword ptr [rbp - 24]
mov rax, qword ptr [rbp - 40] # 8-byte Reload
mov rdi, rax
call _ZN8MyStructC2ERKS_
.LBB0_2:
mov rax, qword ptr [rbp - 32]
cmp rax, 0
mov qword ptr [rbp - 48], rax # 8-byte Spill
je .LBB0_4
# BB#3:
mov rax, qword ptr [rbp - 48] # 8-byte Reload
mov rdi, rax
call _ZdlPv
.LBB0_4:
mov eax, dword ptr [rbp - 4]
add rsp, 48
pop rbp
ret
.Ltmp5:
.size main, .Ltmp5-main
.cfi_endproc
.section .text._ZN8MyStructC2EPd,"axG",@progbits,_ZN8MyStructC2EPd,comdat
.weak _ZN8MyStructC2EPd
.align 16, 0x90
.type _ZN8MyStructC2EPd,@function
_ZN8MyStructC2EPd: # @_ZN8MyStructC2EPd
.cfi_startproc
# BB#0:
push rbp
.Ltmp8:
.cfi_def_cfa_offset 16
.Ltmp9:
.cfi_offset rbp, -16
mov rbp, rsp
.Ltmp10:
.cfi_def_cfa_register rbp
mov qword ptr [rbp - 8], rdi
mov qword ptr [rbp - 16], rsi
mov rsi, qword ptr [rbp - 8]
mov rdi, qword ptr [rbp - 16]
mov qword ptr [rsi], rdi
pop rbp
ret
.Ltmp11:
.size _ZN8MyStructC2EPd, .Ltmp11-_ZN8MyStructC2EPd
.cfi_endproc
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LCPI2_0:
.quad 4614253070214989087 # double 3.1400000000000001
.section .text._ZN8MyStructC2ERKS_,"axG",@progbits,_ZN8MyStructC2ERKS_,comdat
.weak _ZN8MyStructC2ERKS_
.align 16, 0x90
.type _ZN8MyStructC2ERKS_,@function
_ZN8MyStructC2ERKS_: # @_ZN8MyStructC2ERKS_
.cfi_startproc
# BB#0:
push rbp
.Ltmp14:
.cfi_def_cfa_offset 16
.Ltmp15:
.cfi_offset rbp, -16
mov rbp, rsp
.Ltmp16:
.cfi_def_cfa_register rbp
sub rsp, 32
lea rax, qword ptr [.L.str]
mov qword ptr [rbp - 8], rdi
mov qword ptr [rbp - 16], rsi
mov rsi, qword ptr [rbp - 8]
mov rdi, rax
mov al, 0
mov qword ptr [rbp - 24], rsi # 8-byte Spill
call printf
mov rsi, qword ptr [rbp - 24] # 8-byte Reload
cmp qword ptr [rsi], 0
mov dword ptr [rbp - 28], eax # 4-byte Spill
je .LBB2_3
# BB#1:
movsd xmm0, qword ptr [.LCPI2_0]
mov rax, qword ptr [rbp - 24] # 8-byte Reload
mov rcx, qword ptr [rax]
movsd xmm1, qword ptr [rcx]
ucomisd xmm1, xmm0
jne .LBB2_2
jp .LBB2_2
jmp .LBB2_3
.LBB2_2:
mov rax, qword ptr [rbp - 16]
mov rax, qword ptr [rax]
mov rcx, qword ptr [rbp - 24] # 8-byte Reload
mov qword ptr [rcx], rax
.LBB2_3:
add rsp, 32
pop rbp
ret
.Ltmp17:
.size _ZN8MyStructC2ERKS_, .Ltmp17-_ZN8MyStructC2ERKS_
.cfi_endproc
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "Copy-constructorn"
.size .L.str, 18
.ident "Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)"
.section ".note.GNU-stack","",@progbits
读取尚未初始化的变量是未定义的行为。 因此,编译器在赋值之前将指针的值设置为 NULL 并非不合理,这将导致复制构造函数中的 if
语句短路,从而永远不会执行*a
。
调用放置new
是可以的:它应该有什么问题:它获得足够的内存来放置一个对象。当然,它应该使用复制构造函数,因为您以 obj
作为参数调用它。但是,此输出是否出现是悬而未决的:printf()
缓冲其内存,并且由于在此构造后通过调用delete (MyStruct*)ptr;
导致未定义的行为,即在非放置new
未获得的指针上,代码可能很容易在库刷新缓冲区之前崩溃(它打印复制构造函数在我的系统上使用)。
要正确销毁您的对象,您需要使用如下内容:
MyStruct* mptr = new(ptr) MyStruct(obj);
mptr->~MyStrucT();
operator delete(ptr);
实际上,在复制构造过程中,对于a
成员也存在未定义的行为:成员不是隐式复制的。也就是说,您正在访问复制构造函数中的未初始化内存,该内存也可以执行任何它想要的操作。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- sdl软件渲染器不工作,工作在硬件加速的一个