일부 상황부터 살펴 보겠습니다.배치 '새`는 기본 저장소 값에 의존할까요?
사용자 정의 메모리 풀은 다음과 유사한 코드를 사용했다 :
struct FastInitialization {};
template <typename T>
T* create() {
static FastInitialization const F = {};
void* ptr = malloc(sizeof(T));
memset(ptr, 0, sizeof(T));
new (ptr) T(F);
return reinterpret_cast<T*>(ptr);
}
생각 FastInitialization
를 호출 할 때, 생성자는 저장 이미 제로 초기화 있다고 가정 따라서 만 초기화 할 수 있다는 것입니다 다른 가치가 필요한 회원.
GCC (6.2 및 6.3, 적어도) 그러나에 개막에 "흥미로운"최적화를 가지고
struct Memset {
Memset(FastInitialization) { memset(this, 0, sizeof(Memset)); }
double mDouble;
unsigned mUnsigned;
};
Memset* make_memset() {
return create<Memset>();
}
는 아래로 컴파일합니다.
make_memset():
sub rsp, 8
mov edi, 16
call malloc
mov QWORD PTR [rax], 0
mov QWORD PTR [rax+8], 0
add rsp, 8
ret
그러나 :
struct DerivedMemset: Memset {
DerivedMemset(FastInitialization f): Memset(f) {}
double mOther;
double mYam;
};
DerivedMemset* make_derived_memset() {
return create<DerivedMemset>();
}
을
아래로 컴파일 :
make_derived_memset():
sub rsp, 8
mov edi, 32
call malloc
mov QWORD PTR [rax], 0
mov QWORD PTR [rax+8], 0
add rsp, 8
ret
즉, 기본에 해당하는 부분 인 struct
의 처음 16 바이트 만 초기화되었습니다. 디버깅 정보는 memset(ptr, 0, sizeof(T));
에 대한 호출이 완전히 제거되었음을 확인합니다.
make_derived_memset(): # @make_derived_memset()
push rax
mov edi, 32
call malloc
xorps xmm0, xmm0
movups xmmword ptr [rax + 16], xmm0
movups xmmword ptr [rax], xmm0
pop rcx
ret
그래서 GCC와 연타의 행동이 다르며, 문제가된다 : GCC 권리 인 반면에
, 모두 ICC와 연타 모두 전체 크기에 memset
전화, 여기에 연타의 결과입니다 더 나은 어셈블리를 만들거나 Clang right와 GCC 버그가 있습니까?
또는 언어 변호의 관점에서 : 생성자가 할당 된 스토리지에 저장된 이전 값에 의존 할 수
있는 상황에서?
참고 : 게재 위치는 new
이며 문제가 있다고 가정합니다.
코드가 memset (ptr, 0, sizeof (T)) 및 sizeof (T) = 32를 실행하고 16 바이트 만 0이면 분명히 옳지 않습니다. create가 호출 된 후 멤버 변수를 읽는 코드를 추가하려고 했습니까? 그들의 가치는 무엇입니까? –
나는이 질문이 너의 훨씬 더 넓은 질문에 대한 답이 아니라는 것을 안다; 하지만 0으로 초기화하는 경우 : 당신은'calloc'을 시도해 보았습니다. 여기서 memset으로 일어날 수있는 0으로 컴파일러에서 0을 초기화하지 말아야합니까? –
@SvenNilsson : 값은'memset' 호출 이전에 포함 된 메모리로부터 남겨졌으며, 실제 코드에는 포인터가 있었으므로 이제 해제 된 메모리에 포인터가 매달려있었습니다. –