# c++11
[C++] weak_ptr
본 글은 std::weak_ptr의 소개와 간단한 사용법을 중심으로 설명합니다. > > std::weak_ptr 클래스가 갖는 멤버 변수나 함수에 대한 자세한 내용은 시간이 되면 나중에 작성하겠습니다. 설명 std::weak_ptr란? std::weak_ptr 생성시, 제어 블록 std::weakptr는 std::sharedptr에 의해 관리되는 자원 객체를 공유하지만 소유하지 않는 (std::sharedptr의 약점(순환 참조)를 보강해주는)스마트 포인터입니다. 자원 객체를 소유하지 않기 때문에 std::sharedptr로 관리되는 자원 객체를 가리켜도 참조 개수에 영향을 미치지 않습니다(대신 약한 개수(weak count)에 영향을 미칩니다).
[C++] shared_ptr
본 글은 std::shared_ptr의 소개와 간단한 사용법을 중심으로 설명합니다. > > std::shared_ptr 클래스가 갖는 멤버 변수나 함수에 대한 자세한 내용은 시간이 되면 나중에 작성하겠습니다. 설명 std::shared_ptr란? std::sharedptr는 std::uniqueptr와 달리 자원 객체에 대한 공유 소유권(shared ownership) 의미론을 체현한 스마트 포인터입니다. shared_ptr는 하나의 자원 객체를 여러 포인터 객체가 가리킬 수 있으며 모든 포인터 객체가 자원 객체를 필요하지 않을 때 자원 객체를 해제하도록 설계되어 있습니다. 하지만 어느 시점에 모든 포인터 객체가 자원 객체를 필요하지 않은지 알 수 없습니다. std::shared_ptr는 자원 객체를 가리키는 포인터 객체의 수를 참조 개수(reference count)라 명명하고 관리합니다. 참조 개수는 생성자가
정규 표현식 예시
정규 표현식 사용 예시들 이메일 구분 코드 전화번호 ('-' 사용한 전화번호) 숫자만 가능 : [ 0 ~ 9 ] 주의 : 띄어쓰기 불가능 영문만 가능 ^x // '^'은 문자열의 시작을 표현하며, x문자로 시작됨을 의미(그 행의 첫 문자부터 시작을 의미..) x$ // '$'은 문자열의 종료를 표현하며, x문자로 종료됨을 의미 .x // '.'은 개행문자 \n을 제외한 다른 모든 문자를 의미 x+ // '+'은 1회 이상 반복을 의미, x문자가 1번 이상 반복됨을 의미 ({1,}과 동일) x* // '*'은 0회 이상 반복을 의미, x문자가 0번 이상 반복됨을 의미 ({0,}과 동일) x? // '?'은 0 or 1개 문자 매칭 의미, x문자가 존재할 수도 있고 안할수도 있다는 의미 ({0,1}과 동일) x|y // '|'은 or를 표현, x 또는 y가 나온다는 의미 (x) // '()'은 그룹을 표현, 괄호로 묶인 패턴을 의미 ((abc){3
[C++] unique_ptr
본 글은 std::unique_ptr의 소개와 간단한 사용법을 중심으로 설명합니다. > > std::unique_ptr 클래스가 갖는 멤버 변수나 함수에 대한 자세한 내용은 시간이 되면 나중에 작성하겠습니다. 설명 std::unique_ptr란? std::uniqueptr는 가리키는 자원 객체에 대한 유일한 소유권을 갖는 독점 소유권(exclusive ownership) 의미론을 체현한 스마트 포인터입니다. std::uniqueptr은 생 포인터(raw pointer)와 같은 크기로 볼 수 있으며, 대부분의 연산(역참조를 비롯해서)에서 std::uniqueptr는 생 포인터와 동일한 명령을 실행할 수 있습니다. 즉, 메모리와 CPU 주기가 넉넉하지 않은 상황에서도 생 포인터가 충분히 작고 충분히 빠른 상황이라면 std::uniqueptr를 사용해도 비슷한 성능을 낼 수 있습니다. std::unique_ptr는 <u
[C++] Smart Pointer
설명 C#이나 Java같은 프로그래밍 언어에는 가비지 컬렉터(Garbage Collector:GC)라는 자원 청소기가 기본적으로 내장되어 있습니다. 이 가비지 컬렉터는 프로그램에서 더 이상 사용하지 않는 자원을 자동으로 해제하는 역할을 수행하기 때문에 프로그래머가 자원을 해제하는 것에 대한 신경을 쓰지 않아도 됩니다. 하지만 C++에는 이러한 개념이 존재하지 않아 프로그래머가 수동으로 메모리를 해제해야 합니다. 만약 사용한 자원을 해제하지 않으면 프로그램이 종료되기 전까지, 메모리에 계속 남아있는 메모리 누수(Memory leak)가 발생합니다. '프로그래머가 신경 써서 메모리 해제만 했어도 일어나지 않았을 문제 아닌가?' 생각할 수 있습니다. 객관적으로 보자면 신경쓰지 못한 프로그래머의 잘못이 맞습니다. 하지만 우리는 사람이기 때문에 실수로 메모리 해제를 잊을 수도, 언어의 사양을 잘못 파악하거나 예상치 못한 곳에서 다른 흐름이 발생해 메모리가 해제되
[C++] nullptr
설명 nullptr 키워드는 null 포인터를 나타내는 상수 리터럴로 std::nullptrt 타입의 prvalue입니다. nullptr 키워드는 헤더를 포함하지 않고 사용할 수 있지만 std::ptrt 타입을 사용하려면 `` 헤더를 포함해야 합니다. > std::nullptr_t 타입은 암시적으로 모든 타입의 포인터로 형 변환이 가능합니다. NULL의 문제 C++에 객체지향 패러다임이 적용되면서 오버로딩을 지원하게 되면서 NULL을 사용할 때, 문제가 발생하게 됩니다. > 오버로딩을 간단하게 설명하면 똑같은 이름을 사용하지만 다른 매개 변수를 갖는 함수를 뜻합니다. 프로그래머는 NULL을 전달하며 void func(int*)가 호출되는 것을 의도했겠지만 NULL은 0으로 정의된 매크로이기 때문에 void func(int)가 호출됩니다. 하지만 nullptr을 전달할 경우 의도대로 `void fun
[C++] Range-for 문
구문 > for ( element-type element-name : data-list ) element-type - data-list의 요소의 데이터 타입 element-name - data-list의 요소에 접근할 변수명 data-list - 배열, vector 등의 순회가 가능한 데이터 리스트 설명 배열, 벡터 등의 데이터 리스트 자료형을 순회해야 할 때, 보통 인덱스와 데이터 리스트의 길이를 이용합니다. 정확한 인덱스를 설정했다면 문제없지만 프로그래머의 실수로 잘못된 인덱스를 설정한다면 에러가 발생하게 됩니다. 범위기반 for 문은 기존의 for 문과 달리 스스로 데이터 리스트의 처음부터 끝까지 순회하는 반복문입니다. 스스로 순회 범위를 판단하기 때문에 인덱스 실수로 인한 에러를 줄일 수 있습니다. 범위기반 for 문에서 접근한 요소는 값을 복사한 것입니다. 때문에 범위기반 for 문의 본문에서 요소를
[C++] lambda
구문 > [ capture ] ( params ) [:specifiers] [:exception] [:trailing return type] { body } capture - 캡처 params - 매개 변수 [:specifiers] - 변경 가능한 사양 [:exception] - 예외 사양 [:trailing return type] - 후위 반환 형식 body - 본문 설명 lambda expression는 람다(lambda)라고 많이 불리며 함수 객체를 정의하는 편리한 방법입니다. 즉, 익명 함수를 뜻합니다. 람다 식은 일반적으로 알고리즘 또는 비동기 함수에 전달되는 몇 줄의 코드를 캡슐화하는데 사용됩니다. Capture 람다는 캡처를 이용해, 람다 외부에 정의되어 있는 변수나 상수를 람다 내부에서 사용할 수 있습니다. '매개 변수로 전달해 사용하면 되는 것 아닌
[C++] auto
구문 > auto variable-name = initializer ; > auto variable-name = lambda expression|Function Pointer ; [variable-name] - 식별자 initializer - 초기화 할 값 expression - 람다식 설명 auto 키워드는 C++11 이전에는 다른 의미로 사용됐지만, 이후에는 컴파일러가 선언된 변수 또는 람다 식 매개 변수의 초기화 식을 사용하여 형식을 추록하도록 지시하는 키워드입니다. 즉, Java, C#의 'var' 키워드 처럼 초기화 값에 따라 타입을 정해주는 타입 추론 키워드입니다. char, int 등의 기본 타입형과 struct, class 등의 타입까지 추론 가능합니다. 또한 함수 포인터나 함수 자체(람다 함수)도 될 수 있습니다. 다음과 같은 이점을 제공하기 때문에 Vi
[C++] enum class
구문 > scoped enum: > enum [class|struct] [variable-name] [:type] { [enum-list] } ; [class|struct] - 열거형의 범위(scope)를 지정 [variable-name] - 열거형에 지정된 형식 이름 [:type] (옵션, defalut: int) - 열거형의 기본 타입, 모든 열거자는 동일한 기본 형식을 갖고 모든 정수 계열 형식이 가능하다. enum-list - 열거형의 목록 설명 C++11 이전의 enum은 다음과 같은 3가지 문제점을 보여줍니다. enum은 암시적으로 int로 형변환이 되어, 정수로써 작동되기 원하지 않을 때, 오류를 발생시킨다. 허용 범위(scope) 밖에서도 열거자 이름들을 사용할 수 있기 때문에 이름 충돌이 발생한다. 전진 선언(forward declaration)이 불가능하다.

많이 사용하는 모던 C++ 키워드
서문 C++ 언어는 C++11 이 발표되기 전까지 오랜기간동안 정체되어 있었다. 프로그래머가 하나부터 열까지 관리해야되서 사소한 실수(Mistake)에 프로그램이 죽는 대형사고가 빈번했다. 이런 특성 때문에 생산성에서 많이 외면 당한 부분이 많다. 하지만 최근 C++은 많이 발전하고 편리(메모리는 아직...)해졌다. 고전 C++ 에 비해 많은 것이 바뀐 모던 C++ 에서 필자가 자주 사용하는 키워드를 소개해보려고 한다. auto 필자가 애정하는 키워드다. 게임컨텐츠의 데이터 혹은 메모리에 로드하는 리소스 관리를 위해 필연적으로 컨테이너를 사용하게 되는데, 데이터의 구조에 따라 단순하게 unordered_map 이나 vector, list 로 끝나지만, 복잡한 데이터라면 필연적으로 여러개의 컨테이너 구조를 복합적으로 사용하게 된다. 예를 들어 아래와 같은 코드를 보자. 이 코드는 int, vector 을 Key-Value 타입으로 게임데이터를 가지

[C++] 예외 처리
Chapter.10 예외 처리 10.1 try, throw, catch문 C++은 '구조화된 예외 처리'를 지원한다. 10.1.1 기본 활용 방법 try-catch 문은 기본적으로 if문과 큰 차이가 없어보이지만, 예외 처리를 한 곳에 묶을 수 있어 구조적으로 간결한 코드를 만들 수 있다는 장점이 있다. 10.1.2 catch 다중화 try-catch 문에서 catch문은 여러 개로 구현할 수 있는데, 이를 'catch 다중화'라고 한다. 가령 throw문으로 예외를 던질 때 값의 자료형이 int인 경우와 char인 경우를 각각 다른 catch문으로 처리할 수 있다. 적절한 catch문이 없는 경우를 대비하여 다음과 같이 어떤 형식이든 받아들이는 catch문 블록을 만들 수 있다. 10.1.3 예외 클래스 catch문 블록은 값의

[C++] 템플릿
9.1 클래스 템플릿 기본적인 내용은 2장의 함수 템플릿과 동일하나, 인스턴스 선언시에는 typename을 반드시 기술해야 한다는 점이 다르다. 선언 방법 다음 예제를 통해 클래스 템플릿의 활용을 알아보자. 배열 연산자에서는 메모리 오버플로우를 방지하기 위해 오류를 발생시킨다. 단순 대입 연산자는 r-value에 맞춰 메모리를 새롭게 생성하므로 메모리 오버플로우가 발생하지 않는다. 9.1.1 멤버 선언 및 정의 클래스 템플릿에서도 선언과 정의를 분리할 수 있다. 선언부에서 template를 매번 선언해야 한다는 단점이 있다. 9.1.2 템플릿 매개변수 9.2 템플릿 특수화 특정 형식에 대해서는 전혀 다른 코드를 적용해야할 때가 있다. 9.2.1 함수 템플릿 특수화 다음과 같이 형식에 따라 함수 구현을 나

[C++] 상속 심화
7.1 가상 함수 '가상 함수(Virtual Function)'는 virtual 예약어를 앞에 붙여서 선언한 메서드를 말한다. 가상 함수는 '자기 부정'을 전제로 작동한다. 일반 메서드는 참조 형식을 따르고, 가상 함수는 실 형식을 따른다. 가상 함수의 호출은 미래에 파생 클래스에서 재정의될 함수를 호출하는것이다. 가상 함수를 적절히 사용하기 위해선, 해당 함수가 어디에서 호출되는지 파악하는것이 중요하다. 7.1.3 소멸자 가상화 상위 클래스로 하위 파생 클래스를 참조할 때, 심각한 메모리 누수 오류가 발생할 수 있다. 위와 같은 경우에 참조 형식에 해당하는 소멸자(CMyData::~CMyData())만 호출되므로, CMyDataEx의 멤버 변수인 *m_pnData의 메모리는 해제되지 않는다. 메모리 누수 오류 발생 소멸자를 가상화 하여 문제를 해결할

[C++] 상속 기본
6.1 상속이란? 6.1.1 기본 문법 클래스를 선언할 때, 특정 클래스를 상속받으려면 다음과 같이 코드를 작성한다. 파생 클래스의 인스턴스가 생성될 때 기본 클래스의 생성자도 호출된다. 파생 클래스는 기본 클래스의 멤버에 접근할 수 있다. (private 제외) 파생 클래스의 인스턴스를 통해 기본 클래스 메서드를 호출할 수 있다. 상속 관계에서 파생 클래스의 생성자는 먼저 호출되지만 실행은 나중에 된다. 파생 클래스 인스턴스 생성 상위 클래스 생성자 호출 상위 클래스 생성자 실행 및 반환 파생 클래스 생성자 실행 파생 클래스 생성자 반환 private으로 선언된 멤버는 파생 클래스에서 접근이 불가능하다. protected으로 선언된 멤버는 파생 클래스에서만 접근이 가능하며, 외부에서는 접근이 불가능하다. 6

[C++] 연산자 다중 정의
5.1 연산자 함수란? '연산자 함수': 연산자를 이용하듯 호출할 수 있는 메서드 연산자 함수는 절대 오류가 발생해서는 안된다. 절대로 논리 연산자들을 다중 정의해서는 안된다. 5.2 산술 연산자 숫자가 아닌 것도 경우에 따라 사칙연산이 가능할 수 있다! 연산자 함수는 다중 정의가 가능하다. CMyInteger타입과 int 타입의 사칙연산을 지원하고 싶다면 다음과 같이 정의하면 된다. CMyInteger operator+(int param) 사실 cout 객체는 전역 변수로 존재하는 ostream 클래스의 인스턴스고, > 등의 연산자를 제공한다. 5.3 대입 연산자 대입 연산자의 다중 정의 다음과 같은 코드는 문법상의 오류는 없으나, 실행 시 심각한 오류가 발생할 수 있다. 자기 자신에게 단순 대입 연산을 실행하는 것이 적절하

[C++] 복사 생성자와 임시 객체
4.1 복사 생성자 '복사 생성자(Copy Constructor)'는 객체의 복사본을 생성할 때 호출되는 생성자다. 클래스 내부에서 메모리를 동적 할당 및 해제하고 이를 멤버 포인터 변수로 관리하고 있는 경우, 복사 생성자를 적용하지 않으면 문제가 발생할 수 있다. 4.1.1 함수 호출과 복사 생성자 다음과 같은 함수는 복사 생성자의 호출을 유발한다. 위와같은 함수는 프로그램의 성능에 안좋은 영향을 미친다. 다음과 같이 참조자 매개변수를 사용하여 문제점을 보완할 수 있다. 참조자 매개변수는 호출 시점에 해당 함수가 call by reference인지 판단할 방법이 없다. 이럴 경우, 함수를 호출했을때 원하지 않는 값의 변경이 있을 수 있다. 매개변수의 형식이 클래스 형식이라면 상수형 참조로 선언하는것이 좋다. 4.1.2 깊은 복사와 얕은 복사

[C++] 클래스
3.1 객체지향 프로그래밍 개요 3.2 클래스 기본 문법 3.2.1 멤버 선언 및 정의 클래스의 멤버 변수는 '생성자(constructor)'를 통해 초기화 할 수 있다는 점이 구조체와의 큰 차이점이다. 멤버 변수를 초기화 하는 방법 세 가지 생성자를 통한 초기화 생성자 초기화 목록 사용 선언과 동시에 초기화(C++11 이상) 멤버 함수의 선언부와 정의부의 분리 3.2.2 접근 제어 지시자 public: 멤버에 관한 모든 외부 접근 허용 protected: 멤버에 관한 모든 외부 접근 차단. 단, 상속 관계에 있는 파생 클래스에서의 접근은 허용 private: 외부 접근뿐만 아니라 파생 클래스로부터의 접근까지 모두 차단.(접근제어자 미기술시 기본값으로 적용) 3.3 생성자와 소멸자 '생성자(Constructor)'와 '소멸자(Destruct

[C++] C++ 함수와 네임스페이스
2.1 디폴트 매개변수 cpp에서는 함수의 매개변수에 기본(디폴트)값을 지정할 수 있다. 매개변수의 디폴트 값은 반드시 함수 원형의 선언 부분에 기술해야 한다. 매개변수가 두 개 이상일 경우, 피호출자 함수 매개변수의 왼쪽부터 짝을 맞춘다. 따라서, 피호출자 함수 매개변수의 디폴트 값은 반드시 오른쪽 매개변수부터 기술해야 한다. C++에서는 호출자의 코드만 보고 함수 원형을 확정해서는 안 된다! 2.2 함수 다중 정의 cpp에서는 함수 원형이 달라지면 이름이 같아도 서로 다른 함수로 인식한다. 이를 통해 함수의 '다형성'을 지원한다. 2.2.1 다중 정의 일반 cpp의 함수 원형의 구성은 크게 네 가지(반환 형식, 호출 규칙, 함수 이름, 매개변수 구성)이다. 함수 다중 구성에서 함수 이름은 이미 동일하다고 가정하므로, 다음 두 경우에는 다중 구성을 지원하지 않는다.

[C/C++] override, final
override override 키워드는 가상 함수를 상속 받은 하위 클래스의 끝 부분에 붙이는 키워드다. 이 키워드는 컴파일러와 개발자에게 가상 함수를 오버라이딩한 함수라는 뜻을 나타낸다. 가상 함수의 virtual 선언은 상속되므로 오버라이딩 시 (파생 클래스의) virtual을 생략할 수 있다. override 키워드를 주로 사용하는 용도는 Base에 없는 메소드를 오버라이드하려는 실수를 막을 수 있다는 점이다. 위의 Base 가상 함수 func는 int형을 인자로 받지만 파생 클래스의 func은 float형을 인자로 받았다. 오버라이드는 함수의 이름과 시그니처가 모두 동일해야지만 이루어진다. 파생 클래스 func는 인자형을 부모 함수의 int가 아닌 fla