생성자/소멸자에서 virtual 호출은 현재 생성/소멸중인 클래스까지만 적용된다.
즉, 자식의 오버라이딩된 함수가 아닌 같은 레벨의 가상함수가 호출된다.
PageFault란 프로세스가 접근한 가상 메모리 페이지가 현재 물리 메모리에 없을때 발생할 수 있음
lvalue는 이름이 있고 메모리어딘가에 계속 존재해서 접근할 수 있는 값
rvalue는 이름이 없고, 잠깐 만들어졌다가 금세 사라질 임시 값
move는 객체가 가진 자원을 새 객체가 재사용해서 비싼 복사를 피하기 위해서 사용한다.
여기서 중요한게 move는 실제로 값을 옮기는건 아니고 std::move(a)하면 a를 rvalue처럼 취급하도록 변환한다는 의미이다(xvalue)
이동가능한 값으로 취급된 a는 대입했을때 move constructor가 선택되어서 이동연산이 선택되어 복사비용이 없다
string b = std::move(a)로 대입한 a는 여전히 존재하지만 내용은 보장되지 않음
C++에서 코드가 예상하지 못하는 외부 요인에 의해 바뀔 수 있으니, 컴파일러가 값을 마음대로 캐싱하거나 접근을 없애지 말라는 표시
volatile int status;
컴파일러는 보통 변수값을 한 번 읽고 레지스터에 저장한 뒤 재사용하는 최적화를 할 수 있음
volatile이면 status가 외부 장치 같은것에 의해 변경될 수 있으니, 컴파일러에게 실제 값을 계속 확인해야 하는 변수라고 알려주는 것
대표적인 용도는 하드웨어 레지스터처럼 프로그램 외부에서 값이 변할 수 있는 경우
비트/주소를 저수준에서 다른 타입으로 재해석할 때쓰는 캐스팅
int x = 10;
int* p = &x;
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
포인터 주소값을 정수 형태로 바꾸는 식으로 쓸 수 있음
uintptr_t : unsigned integer ptr , 포인터 주소값을 정수로 담을 수 있도록 만든 타입
int* p;
char* c= reinterpret_cast<char*>(p);
서로 다른 포인터 타입으로 강제로 해석할 수도 있다.
#include <string>
#include <vector>
#include <unordered_map>
using namespace std;
int solution(vector<vector<string>> clothes) {
int answer = 1;
unordered_map<string, int> umap;
for (const vector<string> clothe : clothes){
umap[clothe[1]]++;
}
for (const auto& [key, value] : umap){
answer *= (value + 1);
}
return answer - 1;
}