프로그래밍 언어/Effective Modern C++ 8

[Effective Modern C++] 항목 41 ~ 42 : 다듬기

항목 41 : 값 전달 함수가 좋은 경우아래 조건이 만족하면 사용자 정의 클래스 매개변수도 값전달이 유용할 수 있다.1. 이동이 싸다2. 함수가 해당 매개변수를 결국 내부에서 복사하는데 사용한다.3. 복사 가능 타입 예시)class Widget {public: void addName(const std::string& newName) { names.push_back(newName); } void addName(std::string&& newName) { names.push_back(std::move(newName); } ...}class Widget {public: void addName(std::string newName) { names.push_back(std::move(newName)..

[Effective Modern C++] 항목 35 ~ 40 : 동시성 API

항목 36 : std::thread, std::asyncstd::thread t(doAsyncFunctionPointer)는 실제 시스템 스레드를 생성하여 넘겨준 함수 포인터를 실행시킨다. 이러한 std::thead를 활용하는 것을 스레드 기반 프로그래밍이라고 한다. 이때 무조건 시스템 스레드를 생성하기에 스레드 고갈, 과다 구독, 부하 균형화 등의 스레드 관리를 수동으로 모두 해야한다.auto f = std::async( doAsyncFunctionPointer)는 넘겨준 함수 포인터를 사용자 관점에 비동기 동시적으로 테스크라는 단위로써 수행해주는데 무조건 시스템 스레드를 생성하지는 않는다. 대신 내부적으로 알아서 적절하게 시스템 스레드를 할당하고 적절하게 분배하여 수행한다. 따라서 위에서 언급한 스레..

[Effective Modern C++] 항목 31 ~ 34 : 람다 표현식

항목 31 : 기본 캡처 모드를 피하자 기본 캡처 모드란 =이나 &로 모든 값, 참조를 캡처하는 경우를 말한다.우선 당연히 어떤 요소를 캡처하는지 정확히 명시하지 않기에 디자인상 좋지 않다. 참조 캡처의 경우 캡처 대상들의 수명을 잘 관리해야하는데 이는 치명적이다.하지만 더 큰 문제는 값 캡처의 경우에도 수명 관리를 고려해야할 수 있다는 점이다.기본적으로 멤버 함수에서 객체의 멤버는 명시하여 캡처할 수 없다. 하지만 =로 전체 값 캡처를 하면 객체의 멤버에 접근이 가능해진다. 이는 this 포인터가 캡처되고 람다 내에서의 멤버 접근이 자동으로 this->멤버로 수정되기에 가능하다. 그리고 그것은 객체와 객체의 멤버를 참조하므로 객체가 소멸된 상태면 문제를 일으킬 수 있다. 멤버 변수를 진짜 값 캡처하고 ..

[Effective Modern C++] 항목 23 ~ 30 : 이동, 완벽 전달

개요: LValue, RValue이부분은 책의 내용은 아니고 LValue와 RValue에 대한 개념정리를 하면 도움이 될 것 같아 나름대로 해보았다.LValue와 RValue는 2개의 개념으로 분리할 수 있다.1. 한 표현식은 LValue또는 RValue이다.2. 레퍼런스 타입에는  LValue 레퍼런스, RValue 레퍼런스가 있다.이 두개는 연관되어 있지만 별개의 개념이다.예시) RValue 레퍼런스 타입의 변수 하나로 이루어진 표현식은 LValue이다.  레퍼런스 타입에는  LValue 레퍼런스, RValue 레퍼런스가 있다. int&는 LValue 레퍼런스 타입이고int&&는 RValue 레퍼런스 타입이다.  한 표현식은 LValue또는 RValue이다.한 변수의 이름 하나로 이루어진 표현식은 변..

[Effective Modern C++] 항목 18~22 : 스마트 포인터

항목 18 : unique_ptrunique_ptr은 자신이 객체에 대해 유일한 소유권을 가질 때 쓰는 포인터다. 생 포인터를 받거나 make_unique함수를 통해 생성되고 소멸될 때 객체를 같이 소멸시킨다. 이동 연산만 제공하여 자신의 객체를 넘겨주고 자신은 nullptr로 초기화한다.당연히 같은 생 포인터로 여러개를 생성하면 미정의 행동이기에 그러면 안된다. new 구문으로 바로 넘겨주거나 make_unique를 쓰는 것이 권장된다.삭제자를 따로 지정하지 않으면 생 포인터와 동일한 비용이기에 싸다.삭제자를 지정하면 함수 포인터의 경우 1워드, 함수 객체의 경우 그 크기만큼 메모리가 추가 소모된다.갈무리 없는 람다의 경우 추가 메모리가 들지 않기에 유용하다. 항목 19 : shared_ptrshare..

[Effective Modern C++] 항목 7~17 : 현대적 C++

항목 7: 객체 생성 시 ()와 {}를 구분하자.객체 생성 방법1. int x(0);2. int x = 0;3. int x{0};4. int x = {0}; //3과 사실상 동일하기에 3으로 통일하여 설명함. 중괄호 초기화가 소괄호 초기화보다 좋은점1. 모든 초기화 상황에 적용가능함.//비정적 자료 멤버 기본 초기화Class Widget { int x(0); // 에러 int y = 0; // 가능 int z{0}; // 가능}//복사할 수 없는 객체 초기화 (항목 40)std::atomic x(0); // 가능std::atomic y = 0; // 에러std::atomic z{0}; // 가능 2. 좁히기 변환 방지double x,y,z;...int sum1{x+y+z} // double의 합을 int..

[Effective Modern C++] 항목 5~6 : auto

항목 5: 명시적 선언보다 auto를 선호하자.근거1. 긴 타입 타자치기 편함.2. 초기값이 꼭 필요해 초기화 안 까먹음.3. 람다같이 꼭 써야하는 경우가 있음.4. 람다의 경우 std::function을 대신 쓸수도 있지만 메모리가 더 들수있기에 auto가 낫다.5. std::vector::size()의 타입은 size_type인데 윈도우 비트마다 크기가 다르다. 이걸 그냥 unsigned에 담아쓰면 윈도우마다 다른 결과 나올 수 있다. auto쓰면 괜찮음.std::vector v;unsigned sz = v.size() // 윈도우마다 다르게 작동할 수 있음.auto sz = v.size() // good6. map을 아래와 같이 순회하면 tmp 복사본 만들고 그걸 참조함. 성능 안좋음. 이런 실수 ..

[Effective Modern C++] 항목 1~4 : 형식 영역

항목1 : 템플릿 형식 연역형식 연역이란 템플릿, auto등에서 컴파일러가 특정 타입을 유츄해내는 것을 이야기한다. c++은 템플릿, auto, decltype에서 형식 연역이 발생한다. 템플릿의 형식 연역 규칙은 다음과 같다.templatevoid f(T param)//const, 레퍼런스, volatile전부 무시됨.int x = 1;const int cx = 1;const int& rx = x; //세가지 모두 T -> intint* px = &x; // T -> int*const int* px = &x; // T -> const int*const int* const px = &x; // T -> const int*//포인터의 경우 포인터 변수 자체에 대한 const성만 사라짐.templatevoi..