클래스의 디폴트 생성자, 연산자 등을 생기지 않게, 못쓰게 하는 방법.
옛날에는 구현해놓고 private으로 선언해서 못사용하게 만듦.
문법적으로 맞게 막는 방법은 delete
이다. 명시적으로 사용하지 않겠다고 표현하는 문법.
void operator=(const Test& _Other) = delete;
눈에보이진 않지만 분명히 메모리에 존재하는 메모리들을 Rvalue라고 한다.
곧 파괴될 RValue를 깊은 복사하는 불합리한 코드에서 RValue 레퍼런스를 사용해서 생성자나 함수등을 만들면 거기로 들어가서 얕은 복사를 하도록 만들 수 있다...
걔가 RValue라는 건 컴파일러가 알아서 안다.
CreateTest()함수의 반환값인 임시 객체의 NewValue를 NewTest0에 넣고싶은 것이 의도일 때 값을 깊은 복사 하여 넘기는 것은 비효율적이다.
참조로 넘겨주고 임시 객체는 배열에 대한 참조를 잃어버리는 식으로 구현하는 것이 효율적이다. 그리고 이를 &&
가 붙는 RValue Reference를 받는 복사 연산자로 받아 해결할 수 있으며 컴파일러가 알아서 해준다. (아래 코드는 명시적으로 보기 위한 코드)
class Test
{
public:
int* NewValue = nullptr;
Test(Test&& _Other) noexcept
{
int a = 0;
}
Test(const Test& _Other)
{
if (nullptr != NewValue)
{
delete NewValue;
NewValue = nullptr;
}
NewValue = new int[100];
for (size_t i = 0; i < 100; i++)
{
}
}
void operator=(Test&& _Other) noexcept
{
if (nullptr != NewValue)
{
delete NewValue;
NewValue = nullptr;
}
NewValue = _Other.NewValue;
_Other.NewValue = nullptr;
return;
}
void operator=(const Test& _Other)
{
if (nullptr != NewValue)
{
delete NewValue;
}
NewValue = new int[100];
for (size_t i = 0; i < 100; i++)
{
}
return;
}
Test()
{
NewValue = new int[100];
}
~Test()
{
if (nullptr != NewValue)
{
delete NewValue;
NewValue = nullptr;
}
}
};
Test CreateTest()
{
Test NewTestG;
return NewTestG;
}
int main()
{
Test NewTest0 = Test();
NewTest0 = CreateTest();
}
예외를 대처할 수 있는 문법이다. 예외를 외부에서 터진 것으로(?) 만들 수 있다.
try에서 실행한 구문에 예외가 발생하면 catch문에 있는 코드를 실행한다.
예외가 throw될 수 있는 코드를 try내부에 넣는다. throw가 발생하면 catch내부를 실행한다.
#include <iostream>
void Function2() throw(int, bool) //<- int, bool 예외를 throw할 수 있는 함수라는 뜻, 명시하는 용이지 문법은 아님
{
int* Ptr = nullptr;
if (nullptr == Ptr) {
throw 0;
}
*Ptr = 100;
throw true;
}
void Function1()
{
Function2();
}
void Function() // 예외처리 중 받을 구문들을 적어줘야 한다.
{
// 보통 이안에서 내가 뭔가 잘못된것을 느겼다.
try
{
Function1();
}
catch(int ex)
{
// int 예외
std::cout << "int 예외 " << ex << std::endl;
}
catch (bool ex)
{
// bool 예외
std::cout << ex << std::endl;
}
}
try catch와 throw는 최신 문법이라 winapi에는 거의 없다.
많이 사용하는 클래스나 코드의 형태가 있다면 템플릿으로 만들어놓고 사용할 수 있다.
클래스의 디폴트 멤버함수들과 접근지정자 등을 명시해주는 것이 좋지만 매번 새로 쓰기 쉽지 않다. 템플릿을 만들어서 클래스(또는 어떤 코드)를 만들자마자 모든 준비가 끝나있는 상태가 되도록 만들 수 있다.
원본이 되어줄 클래스가 필요하다.
프로젝트 탭 > 템플릿 내보내기 > 항목 템플릿
다음 > 'DefaultClass.h'선택 > 다음 > 마침
(헤더 먼저 할거임)~\Visual Studio 2022\My Exported Templates
위치에 백업폴더 생김.$rootnamespace$
를 $safeitemname$
로 모두 바꾸기 (생성하는 이름으로 클래스와 헤더 만들어주는 역할)$rootnamespace$
를 $safeitemname$
로 모두 바꾸기$rootnamespace$
를 $safeitemname$
로 모두 바꾸기윈도우는 우리에게 절대로 포인터를 주지 않는다. 정수를 준다. 사용하기 위해 전역변수로 받아놓는다.
ex) 너는 xx번 프로그램이야. : HINSTANCE hInstance
window창을 만드는 CreateWindow함수를 호출하면 xx번 프로그램에서 xxxx번 윈도우를 띄운다는 의미로 핸들을 준다. : HWND hWnd
hdc
: 윈도우를 그릴 수 있는 권한
GetMessage 함수 : 윈도우에서 이용자가 어떤 변화를 주면 뭔가를 한다. 동기함수.
while문 안에 있는 if문에 중단점을 걸어도 중단점에 걸리지 않는다. GetMessage함수 때문이다.
(중단점에 걸린다면 윈도우가 생성된 후 선택됐다는 일이 발생한 것이기 때문이다.)
일반적인 게임에서는 윈도우에 변화가 있건 없건 계속 몬스터는 움직여야 하고 나를 때려야 한다.
함수 포인터를 이용한다.
윈도우 => 개발자가 이 윈도우로 뭘 하고 싶은지 알 수 없음. 함수 포인터를 넣어주면 윈도우에 어떤 일이 생겼을 때 그걸 대신 실행해줄게.
wcex.lpfnWndProc
에 함수 포인터를 넣어주면 윈도우에 뭔 일이 있을 때 실행된다?
WndProc 대신 다른 함수 포인터를 만들어서 넣을 수 있다.