반응형

C++ 코드를 보다보니 [[ ~ ]] 와 같은 형식으로 작성된 부분 있었다.

 

뭔가 싶어서 검색해보니 컴파일러에게 코드에 대해서 좀 더 명확하게 힌트를 제공하는 기능이라고 한다.

 

그중에서 자주 사용할것 같은 attribute만 간단하게 정리해보고자 한다. (개인적인 기준;;)

 

1. [[nodiscard]] - C++17

 

이 attribute가 붙은 함수나 attibute가 붙은 enum, class등을 리턴하는 함수를 만들었다면

해당 함수를 호출할때는 리턴값을 받아야 한다고 컴파일러에 알려주는 것이다.

이는 컴파일 시점에 워닝으로 알려준다.

 

[[nodiscard]] int strategic_value(int x, int y) { return x^y; }

int main()
{
  strategic_value(); // warning
  auto v = strategic_value(); // ok

  return 0;
}

 

[[nodiscard("string"]] - C++ 20은 워닝 메시지에 "string" 부분도 같이 남겨준다.

 

2. [[deprecated]] / [[deprecated("string") - C++14

 

해당 attribute가 붙은 함수를 사용하면 사용은 가능하지만 앞으로 제거될 수 있음을 워닝으로 알려준다.

엔진이나 라이브러리를 만들때 많이 사용될 것 같다.

언리얼 엔진에서도 버전업 하고 빌드해보면 나올때가 있다. 그러면 최신에 맞게 코드를 수정해주곤 한다.

 

[[deprecated]]
void TriassicPeriod() {
    std::clog << "Triassic Period: [251.9 - 208.5] million years ago.\n";
}
 
int main()
{
    TriassicPeriod(); // warning
    return 0;
}

 

3. [[fallthrough]] - C++17

 

switch / case 문을 사용하다보면 fallthrough 기능을 사용하곤한다.

컴파일러에 따라서 해당 부분을 워닝처리할때가 있는데 컴파일러에 명확하게

내가 fallthrough를 한거니까 워닝처리를 하지 말라고 하는 것이다.

 

void f(int n) {
  void g(), h(), i();
  switch (n) {
    case 1:
    case 2:
      g();
     [[fallthrough]];
    case 3: // no warning on fallthrough
    ..
  }
}

몇가지 더 있기도 하고 추가될 예정인것 같지만 일단 이정도만 알고 사용해도 되지 않을까 싶다.

반응형
Posted by msparkms
,
반응형

C++은 메모리를 직접 관리할 수 있는 언어이다.

직접 관리는 자유를 주는 대신 책임도 따른다.

메모리를 직접 관리하면 실수에 의해 누수가 일어날 수 있다.

이를 막기 위해 가비지 컬렉션등 메모리 관리를 하는 알고리즘을 구현하거나 라이브러리등을 가져와야한다.

 

C++의 스마트 포인터를 이용하면 포인터를 사용하는 것 처럼 사용할 수 있으면서 (연산자 오버로딩)

메모리 관리는 스마트 포인터 객체에게 맡길 수 있다.

 

스마트 포인터 종류를 간단히 정리해보자.

보통 메모리 누수가 발생하는 이유는 해당 메모리를 바라보는 포인터들이 여러개일 경우

맨 마지막에 해당 메모리에 접근한 포인터가 메모리를 해제해야하는데 이를 관리하기가 쉽지 않다.

 

그래서 사용하는 전략이 대표적으로 두가지가 있는데

해당 메모리를 바라보는 포인터는 무조건 하나만 존재하게 만드는 고유 소유권 방식과

해당 메모리를 바라보는 포인터가 생기면 카운트를 올려주고 해제하면 카운트를 내려서

카운트가 모두 제거되었을때 실제 메모리를 제거해주는 레퍼런스 카운팅 방식이 있다.

 

다른 이유는 delete를 하기전에 예외등이 발생하여 delete가 실행이 안되는 경우이다.

이때는 스마트 포인터 객체로 감싸져 있기 때문에

예외가 발생했을때 해당 객체가 제거되고 메모리 해제부분이 실행되어 해결이 된다.

 

unique_ptr은 고유 소유권 방식의 스마트 포인터이다.

C++14부터 잘 지원되는 auto와 std::make_unique()를 이용하면 쉽게 unique_ptr을 생성할 수 있다.

make_unique()를 이용하면 생성자의 인자를 바로 넘겨줄 수 있어 간단하고

한번 감싸져 있는 형태여서 예외가 발생했을때 누수가 발생할 염려도 없다.

 

기본적인 사용법은 아래와 같다.

기본적으로 포인터와 같은 연산자를 이용할 수 있다.

get()을 통해 내부의 포인터를 직접 얻어올 수 있다.

reset()을 통해 내부 포인터를 해제하거나 내부 포인터를 다른 포인터로 교체할 수 있다.

release()는 내부 포인터를 돌려주며 소유권을 끊어주어서 직접 해제해야 한다.

class Test
{
public:
	Test(int x) : x_(x) {};

	void Print()
	{
		std::cout << x_ << std::endl;
	}

private:
	int x_;
};

void PrintTest(std::unique_ptr<Test> testPtr)
{
	testPtr->Print();
}

int main()
{
	auto myTest = std::make_unique<Test>(1);
	myTest->Print();

	PrintTest(std::make_unique<Test>(2));

	myTest.get()->Print();		// internal pointer
	myTest.reset();			// to nullptr
	if (!myTest)
	{
		std::cout << "myTest is empty" << std::endl;
	}
	myTest.reset(new Test(3));	// to new pointer
	myTest->Print();

	auto myInternalTest = myTest.release();
	if (!myTest)
	{
		std::cout << "myTest is empty" << std::endl;
	}
	myInternalTest->Print();
	delete myInternalTest;		// manually delete

	return 0;
}
반응형
Posted by msparkms
,