CppBasic
go home! :house_with_garden:
C++ Basic
목차
gtest
modern c+ framework 분석
default, delete 키워드
C++ Casting
enum class
emplace_back
vspush_back
typedef
vsusing
C++11 다양한 초기화 방식
C++11의 Thread-Safe SingleTon
C++ Getter, Setter
C++11/14 변경 사항
C++ 14 Digit seperator
익명 함수 문법(Lambda)
tuple (pair의 발전형)
smart pointer
확장할 수 있는 난수 생성기의 추가 : random 헤더 파일
Thread, async future
boost:: asio, multi_index
gtest
특징
Google에서 개발된 C++ 테스트 프레임 워크
Git에서 다운받아서 헤더파일 추가해서 사용
간단한 사용 방식은 다운 받아서, 검증해야할 부분을 검증하면 됨
사용하기 편하게 라이브러리를 덮어서 만들면 더 좋음, Test Fixture
구글에서도 실제로 사용 중 (Chrom)
항상 맞다고 생각하는 부분은 꼭 테스트 코드를 작성해야 함 (DB, Socket 통신 등등)
테스트 코드를 다 통과하더라도 버그가 없는 건 아니다.
사실 상 및에 참고 자료 정독하면 다 이해 됨
참고
modern c+ framework 분석
C++ Casting
static_cast<>()
static_cast<>()
기본적으로 c 타입의 캐스팅과 비슷함
기본 데이터 타입간의 변환
상속 관계의 클래스 계층 간의 변환
다형성 없어도 가능
void 포인터를 다른 포인터로 변환
const_cast<>()
const_cast<>()
포인터의 상수성을 제거 할 때 사용 (const를 제거함)
dynamic_cast<>()
dynamic_cast<>()
상속 관계 안에서만 사용 가능
하나 이상의 가상함수를 가지고 있어야 함
컴파일러의 RTTI 설정이 켜져 있어야 함
캐스팅에 실패할 경우 포인터면 nullptr을 return, 참조자면 bad_cast 예외를 던짐
안전한 캐스팅
매우 느림! (사실 캐스팅에 자신있다면 잘 안쓰고 거의 static_cast를 사용)
reinterpret_cast<>()
reinterpret_cast<>()
C 스타일 캐스팅과 거의 완전 같음
걍 다됨
하지만! const_cast는 안 됨
다 되기 때문에 위험함, 얘도 안 쓰는게 좋음
거의 static_cast를 위주로 사용하는 것이 좋다
Enum Class
Enum의 범위를 제한하기 위해 Enum Class를 사용한다.
FeatureSolid 참조할 것
emplace_back vs push_back
emplace_back
함수를 생성하지 않고 가변 인자를 받을 수 있다.
받은 인자를 가지고 vector 내에서 객체를 생성한다.
push_back
함수를 생성한 뒤 객체 자체를 인자로 넘겨야 한다.
내부 적으로 생성된 뒤 생성자와 소멸자가 2번 씩 불리기 때문에 비효율적이다.
However
push_back으로 하여도 최신 컴파일러 내부적으로 최적화 하기 때문에 emplace_back으로 하는 것과 별차이가 없을 수 있다. 고로 개인 프로젝트가 아니라면 호환성이 더 좋은 push_back 사용이 더 나을 수도 있다.
push_back함수로 할 수 있는 모든 것을 emplace_back으로 할 수 있다.
typedef vs using
typedef
typedef 키워드의 문법은 앞의 타입형을 뒤에 있는 이름으로 축소해서 사용하겠다는 것
using
약간 변수 할당과 비슷한 느낌으로 MyClassPtr에 std::shared_ptr를 대입하는 것
result
typedef는 템플릿이 안되지만 using은 된다.
코드 구성 자체도 using이 훨신 직관적이다.
modercpp를 쓴다면 typedef말고 using을 사용하도록 하자
C++의 다양한 초기화 방법
복사 초기화
직접 초기화
이니셜라이져처럼 동작, 복사 초기화보다 성능이 뛰어남
이니셜라이징과 대입을 구분할 수 있는 좋은 방법
그러나 위의 두 방식은 모든 변수에 대해서 초기화하지는 않음 모든 타입이나 변수를 초기화 할 수 있는 매커니즘이 필요.
C++11 다양한 초기화 방식
형 변환을 허용하지 않아 안전함.
숫자 변수는 0(또는 0.0 또는 0.0000000000 등)으로 초기화됩니다.
Char 변수는 ‘\0’으로 초기화됩니다.
포인터는 nullptr로 초기화됩니다.
배열, POD 클래스, 구조체 및 공용 구조체는 멤버 값을 0으로 초기화합니다.
static (tip)
정적 변수는 암시적으로 0으로 초기화 됨
Code In 초기화
심플한 초기화는 복사 초기화를 이용한다.
생성자의 경우나, 특별한 로직이나 가독성을 봤을 때 심플하지 않을 때, 직접 초기화를 이용한다.
일반 NULL 초기화의 경우 유니폼 초기화를 이용한다.
유니폼 초기화의 경우 auto와 같이 쓰지 않을 것을 유의한다.
C++11의 Thread-Safe SingleTon
friend class와 GetInstance를 private으로 바꾸면 Singleton 클래스를 한곳에서 받을 수 있는 Handler 클래스를 만들 수 있음
SingleTon.h
SingleTon.cpp
C++ Getter, Setter
왜인지는 잘 모르겠는데 자바 만큼 모든 것을 캡슐화하지는 않음
예제
C++11/14 변경 사항
C++11/14 문법적 변경 사항
초기화 리스트 및 초기화 방법의 통합
새로운 타입의 추가 : long long형 정수
새로운 스마트 포인터 추가 :
널 포인터 상수 추가 : nullptr
열거체의 범위 지정
자동 타입 변환 : auto
타입 변환 연산자 추가 : explicit
범위 기반 for 문 추가
람다 함수와 람다 표현식 추가
C++11/14 표준 라이브러리 변경 사항
확장할 수 있는 난수 생성기의 추가 : random 헤더 파일
튜플 템플릿의 추가: tuple 헤더 파일
정규 표현식의 추가 : regex 헤더 파일
다중 프로그래밍을 위한 스레드의 지원 : thread_local 키워드, automic 헤더 파일
비동기식 프로그래밍 async future 지원
임베디드 프로그래밍을 위한 저수준 프로그래밍 지원
C++ 14 Digit seperator (수 분리자)
익명 함수 문법(Lambda)
기본 구조
3번의 mutable 위치에는 default로 constexpr가 들어간다. (캡쳐할 때 상수로 캡쳐할 것인지 아닌지를 결정)
lambda의 반환
변수 반환
lambda 함수 반환 (std::function)
lambda 함수를 Parameter로 사용
lambda를 STL container에 저장
캡쳐
특징
캡쳐는 람다 밖의 변수를 사용하기 위한 문법이다.
&
는 참조로 캡쳐,=
은 복사로 캡쳐한다.=
로 캡쳐할 경우 람다 body 안에서 변수는 상수로 취급된다. 그 이유는 mutable 자리에 default로 constexpr로 되어있기 때문이다. 그 자리에 mutable로 변경할 경우 복사된 값을 변경할 수 있다.default-capture
로서[&][=]
같은 것들은 전역 변수를 포함해서 외부의 모든 변수를 캡쳐한다.직접 변수를 명시할 경우 람다 바로 부모의 함수 변수들만 캡쳐한다.
문법
[a,&b]
a를 복사로 캡처, b를 참조로 캡처.[this]
현재 객체를 참조로 캡처.[&]
바디에서 쓰이는 모든 변수나 상수를 참조로 캡처하고 현재 객체를 참조로 캡처.[=]
바디에서 쓰이는 모든 변수나 상수를 복사로 캡처하고 현재 객체를 참조로 캡처.[]
아무것도 캡처하지 않음.
예제
default-capture
가 아닌 경우
클래스 멤버 함수 속 lambda
this 를 통한 캡쳐로, 현재 객체를 참조로 캡쳐할 수 있다.
lambda 재귀
재귀 방식을 이용할 경우 auto
를 이용해 람다의 함수를 받을 수 없다.
정리
lambda는 익명 함수(anonymous function)이고 함수 객체를 생성한다.
lambda는 함수 포인터와 함수 객체의 장점을 모두 가지고 있다.
기본 캡처 모드
(capture-default)
, 복사, 참조를 통해 변수나 상수를 캡처할 수 있다.함수에서 반환할 수도 있고 함수의 파라미터로 전달할 수도 있다.
클래스 멤버 함수안에서 정의되는 lambda는
[this]
로 현재 객체를 참조로 캡처할 수 있다.재귀 호출이 가능하다.
tuple
원래는 boost 문법인데 C++11이후로부터 표준으로 채택되었다.
2개 이상의 값을 반환하거나 전달할 때 사용하면 유용하다.
참고로 C++ 14 문법은 요소 하나 조회가 복잡하다. C++ 17이니까 쉽다.
cpp17 설정은 cpp17.md
참고
smart pointer
사용 이유
기존 C++ 프로그램에서 new 키워드를 사용하여 동적으로 할당받은 메모리는, 반드시 delete 키워드를 사용하여 해제해야 했습니다. 때문에 언제든 메모리 누수의 위험이 있었습니다. 이런 문제를 줄여주고자 C++에서는 메모리 누수(memory leak)로부터 프로그램의 안전성을 보장하기 위해 스마트 포인터를 제공하고 있습니다.
스마트 포인터(smart pointer)란 포인터처럼 동작하는 클래스 템플릿으로, 사용이 끝난 메모리를 자동으로 해제해 줍니다.
동작 원리
스마트 포인터를 이해하기 위해서는 스마트 포인터는 새로운 포인터가 아니라, 기본 포인터를 소유한 포인터라고 이해하셔야 합니다.
기본 동작은 new 키워드를 사용해 기본 포인터(raw pointer)가 실제 메모리를 가리키도록 초기화한 후에 스마트 포인터가 기본 포인터를 소유합니다. 이렇게 정의된 스마트 포인터의 수명이 다하면, 소멸자는 delete 키워드를 사용하여 할당된 메모리를 자동으로 해제합니다.
따라서 new 키워드가 반환하는 주소값을 스마트 포인터가 소유하면, 따로 메모리를 해제할 필요가 없어집니다.
예제입니다.
예제에서와 같이 스마트 포인터는 스택에 선언되고, 힙 할당 객체를 가리키는 기본 포인터를 스마트 포인터가 소유합니다.
종류
unique_ptr
shared_ptr
weak_ptr
스마트 포인터는 <memory>
헤더 파일의 std 네임스페이스에 정의됩니다.
unique_ptr
unique_ptr은 하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록 구성된 스마트 포인터입니다.
예제입니다.
특징
기본 포인터에 대한 하나의 소유자만 존재하는 포인터
때문에 소유자를 추가하는 대입 연산이나 복사 생성자는 컴파일러 에러
소유권을 옮길 때는
move
사용합니다.미리 해제하는
reset
함수도 있습니다.스마트 포인터의 접근은
.
을 이용한 접근 연산자로 접근,->
는 소유 객체에 대한 접근make_unique()
는 c++14 이후에 만들어진 함수, 인스턴스를 안전하게 생성할 수 있습니다.보통 대부분의 포인터는
make_unique()
를 이용한unique_ptr
입니다.
shared_ptr
shared_ptr은 하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지를 참조하는 스마트 포인터입니다. 이렇게 참조하고 있는 스마트 포인터의 개수를 참조 횟수(reference count)라고 합니다. 참조 횟수는 특정 객체에 새로운 shared_ptr이 추가될 때마다 1씩 증가하며, 수명이 다할 때마다 1씩 감소합니다. 따라서 마지막 shared_ptr의 수명이 다하여, 참조 횟수가 0이 되면 delete 키워드를 사용하여 메모리를 자동으로 해제합니다.
예제입니다.
특징
스마트 포인터 자체에 접근하여
.
(을 통한 접근)use_count()
함수를 이용하면 참조 하고 있는 레퍼런스 카운트를 알 수 있습니다.레퍼런스 카운트가 0이되면 힙영역에 할당된 메모리를 해제합니다.
복사 생성자를 통한 초기화가 가능합니다. (레퍼런스 카운트 + 1)
대입 연산자를 통한 초기화가 가능합니다.. (레퍼런스 카운트 + 1)
마찬가지로 해제는 스마트 포인터 자체에 접근하여
.
(을 통한 접근)reset()
함수를 이용하거나, 해당 Stack 영역에 할당된 스마트 포인터가 스택에서 빠지면서 해제됩니다. 그것은 레퍼런스 카운트가 -1이 됨을 의미합니다.
this ptr -> shared ptr
한 클래스 내에서 자신의 포인터를 스마트 포인터로 만들어 생성하기
~~~
class Good : public std::enable_shared_from_this {
public: std::shared_ptr create() { return shared_from_this();};
};
특징
순환 참조, 상호 참조시에 레퍼런스 카운트가 0이 되지 않는 경우를 방지하기 위해 사용
나머지 경우는 잘 모르겠음..
Smart Pointer to Nomal Pointer
std::shared<int> intPointer : int *ipVal
std::shared<int> intPointer : int iVal
참고
확장할 수 있는 Random 헤더 파일
쉽다.
예제입니다.
Thread
일단 기달...
async future
일단 기달...
boost:: asio
네트웍 프로그래밍
I/O와 같이 시간이 걸리는 처리를 OS의 비동기 기능과 스레드를 사용하여 처리
C++20에 들어온다고 하는 얘기가 있음
boost:: multi_index
하나의 객체를 여러 키로 적용하여 사용하고 싶을 때
예를 들어 캐릭터의 ID로 검색하거나, 캐릭터의 이름으로 검색하고 싶을 때
Last updated
Was this helpful?