목록Tutorials/C++ : Beginner (46)
KoreanFoodie's Study
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! 파이프라이닝 다음과 같은 코드가 있다고 하자. int a = 0; int b = a + 1; a = 1; 직관적으로는 b = a + 1 이 a = 1 보다 먼저 실행될 것 같지만, 컴파일러가 어셈블리 언어로 번역한 것을 보면 a = 1 이 더 먼저 실행되기도 한다. 물론 b 와 a 에는 각각 1이라는 값이 제대로 들어가지만, 컴파일러는 작업의 효율성을 위해 코드의 실행순서를 변경한다. 이를 파이프라이닝이라고 부른다. 이는 최적화를 위해 어셈블리 명령어를 효율적으로 배치하는 과정을 의미한다. 수정 순서(Modification Order) 명령어를 뒤죽박죽으로 실행하는데도 어떻게 제대로..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! Race Condition 서로 다른 쓰레드에서 같은 메모리를 공유할 때 발생하는 문제를 경쟁 상태(race condition) 이라고 부른다. 다음 코드를 보자. #include #include #include void worker(int& counter) { for (int i = 0; i < 10000; i++) { counter += 1; } } int main() { int counter = 0; std::vector workers; for (int i = 0; i < 4; i++) { // 레퍼런스로 전달하려면 ref 함수로 감싸야 한다 (지난 강좌 bind 함수 참조) ..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! 프로세스와 쓰레드 CPU 코어에서 돌아가는 프로그램 단위를 쓰레드(Thread) 라고 부른다. 즉, CPU 의 코어 하나에서는 한 번에 한 개의 쓰레드의 명령을 실행시키게 된다. 프로세스는 여러 개의 쓰레드로 이루어지는데, 프로세스와 쓰레드의 차이는 메모리를 공유하느냐 하지 않느냐의 차이이다. 각 코어에서는 코어가 돌아가는데, 컨텍스트 스위칭 (Context Switching) 을 통해 쓰레드가 번갈아가며 실행된다. 병렬화(Parallelizable) 가능한 작업 쓰레드를 이용해 병렬화를 적용하면 더욱 빠른 작업이 가능한 경우가 있다. 예를 들어, 다음과 같이 피보나치 수열을 구하는..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! Callable Callable 이란, 이름 그대로 호출(Call)할 수 있는 모든 것을 의미한다. 대표적인 예시로 함수가 있다. 하지만 C++에서는 ( ) 를 붙여 호출할 수 있는 모든 것은 Callable 이라고 정의한다. #include struct S { void operator()(int a, int b) { std::cout
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! shared_ptr 어떤 객체의 경우, 여러 포인터에서 참조를 하여 사용하는 경우가 있다. 이때, 해당 객체를 참조하는 포인터의 수가 0이 되었을 때 해당 객체를 메모리로부터 해제해주는 포인터가 필요한데, 이것이 바로 shared_ptr이다. std::shared_ptr p1(new A()); std::shared_ptr p2(p1); // unique_ptr 일 경우 소유권 문제로 컴파일 오류가 발생한다. std::unique_ptr p3(new A()); std::shared_ptr p4(p3); // 컴파일 오류 위 사진처럼, shared_ptr 는 같은 객체를 가리킬 수 있고..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! Resource Acquisition Is Initialization - RAII 자원의 획득은 초기화다. 이는 자원 관리를 스택에 할당한 객체를 통해 수행하는 것이다. 함수 내부에서 예외가 발생해서 소멸자가 호출하는 코드에 도달하지 못하더라도, 해당 함수의 스택에 정의되어 있는 모든 객체들은 빠짐없이 소멸자가 호출된다(stack unwinding). 만약 이 소멸자들 안에 다 사용한 자원을 해제하는 루틴을 넣으면 어떨까? A* pa = new A(); 예를 들어, 위의 포인터 pa의 경우, 객체가 아니므로 소멸자가 호출되지 않는다. 그 대신, pa를 일반적인 포인터가 아닌, 포인터..
Move 문법 (Move semantics) Swap function을 구현해보자. 일반적인 타입 T에 대한 Swap function은 다음과 같이 구현할 수 있다. template void swap(const T& a, const T& b) { T tmp(a); a = b; b = tmp; } 이 경우, T에서 a를 호출하는 과정에서 복사 생성자가 호출된다. 이 문제를 해결하기 위해, 에서 제공하는 move 함수를 사용한다. template void swap(T& a, T& b) { T tmp = std::move(a); b = std::move(a); a = std::move(tmp); } 위와 같은 방식으로 swap 함수를 구현하면, swap이 실제로 행해지는 과정에서 이동 생성자가 호출된다. mo..
좌측값과 우측값 C++에서, 값은 대체로 우측값과 좌측값으로 나뉘어진다. (더 구체적인 분류는 이곳을 참조) 좌측값은 '이름'을 가지고 있는 녀석, 우측값은 '이름'이 없는 녀석이다. 이동 생성자와 우측값 레퍼런스 클래스에서 생성자를 호출한다고 해 보자. 만약 클래스가 String 변수값을 가지고 있다면, 이미 생성된 변수 a를 이용해 b를 만든다고 할 때 String 값을 매번 새로 생성하는 것은 메모리 낭비이다. 새로운 String을 담을 메모리를 할당하는 대신, 포인터를 전달함으로써 효율적으로 값을 옮기며 클래스 객체를 생성할 수 있는데, 이때 이동 생성자를 사용한다. 이동 생성자는 아래와 같은 형식을 가진다. 우측값 레퍼런스의 경우, typename && var 같은 형식으로 표현되는데, 이때 &..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! throw 로 예외 발생시키기 예외를 발생시키는 예시 코드를 보자. // 생략 ... const T& at(size_t index) const { if (index >= size) { // 예외를 발생시킨다! throw std::out_of_range("vector 의 index 가 범위를 초과하였습니다."); } return data[index]; } 위에서는 범위 초과를 알리는 메시지를 출력한다. C++ 는 예외를 던지고 싶다면 throw 로 예외로 전달하고 싶은 객체를 써주면 된다. C++ 표준에는 overflow_error, length_error, runtime_error ..
모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! std::string std::string 이란 무엇일까? 사실 std::string 은 basic_string이라는 클래스 템플릿의 인스턴스화 버전이다. basic_string definition 은 다음과 같다 : template class basic_string; Traits 는 주어진 CharT 문자들에 대해 기본적인 문자열 연산들을 정의해 놓은 클래스를 의미한다. 여기서, Traits를 바꾸면 정렬 순서를 바꿀 수 있는 등 여러가지 조작을 할 수 있다! 다시 말해, basic_string 에 정의된 문자열 연산들은 사실 전부 Traits 의 기본적인 문자열 연산들을 가지고 ..