C++(15)
-
Placement New로 인해 발생할 수 있는 Undefined Behavior 및 솔루션
C/C++에서는 갖가지 상황에서 Undefined Behavior가 발생할 수 있다. 그 중 대다수에 포인터가 연관되어 있는데, 오늘은 특정 상황에서 Undefined Behavior를 우회하는 방법을 살펴 볼 것이다. 1. Reusing dynamic storage occupied by a const complete object 상수로 선언된 변수의 값을 수정할 수 없다는 것은 알고 있을 것이다. 하지만, 놀랍게도 다음과 같이 placement new를 통해 상수의 값을 강제로 덮어씌울 수 있다. struct X { int n; }; const X *p = new const X{3}; const int a = p->n; new (const_cast(p)) const X{5}; const int b = ..
2022.03.09 -
Placement New를 통해 Trivial 객체를 올바르게 복사하는 방법
[원문 링크] 위 링크에서는 다음 질문을 하고있다. T가 trivial 타입이면 memcpy를 통해 오브젝트를 복사할 수 있으며, trivial 타입의 default initialization은 오브젝트의 representation을 변경하지 않으므로, 아래의 코드는 복사된 오브젝트를 올바르게 초기화 하는가? template T* copy_trivial(T orig) requires std::is_trivial_v { void* buf = std::aligned_alloc(alignof(T), sizeof(T)); // Note the order of these statements std::memcpy(buf, &orig, sizeof(T)); return new(buf) T; } 위 코드는 다음과 같이..
2022.03.03 -
Compiler Explorer를 통한 어셈블리 분석
이 포스트에서는 간단한 예제로 Compiler Explorer에서 생성된 어셈블리를 분석해본다. 생성되는 어셈블리는 각 컴파일러 마다 다르며, 함수로 인자가 넘겨지는 방식이나 스택에 메모리가 얼마나 할당되는지 등은 함수 호출규약(Calling Convention)에 따라 다르므로, 여기서는 생성된 어셈블리에서의 각 숫자에 의미를 부여하는 것 보다는 어셈블리가 어떻게 구성되는지를 보도록 한다. 이 포스트에서 컴파일러는 clang(x86-64)을 사용하며, 예제로 사용할 소스코드는 다음과 같다. 먼저 main() 함수의 어셈블리를 보자. 빨간색으로 표시된 영역(19~21)을 함수의 프롤로그(prologue)라고 하며, 함수를 시작하기에 앞서 필요한 레지스터와 로컬 변수들 사용을 위해 필요한 스택 영역을 설정..
2022.03.01