728x90
반응형

C++ 161

[C++] recursive_mutex

std::mutex의 lock()의 경우 lock을 호출한 함수에서 unlock을 호출하지 않고 또다시 lock을 호출하면 알 수 없는 동작을 하게 된다고 한다. 예를 들면 아래와 같다. class buffer { list queue; std::mutex mut; public: bool empty() { std::lock_guard lock(mut); return queue.empty(); } // 생략 int pop() throw(out_of_range) { std::lock_guard lock(mut); while (empty()) { // 생략 } int tmp = queue.front(); queue.pop_front(); return tmp; } }; buffer 클래스에서 pop() 함수를 호..

[C++] result_of

지정된 인수 유형을 사용하는 호출 가능 형식의 반환 형식을 결정한다. template struct result_of; // Causes a static assert template struct result_of; // Helper type template using result_of_t = typename result_of::type; Fn : 쿼리할 호출 가능 형식 ArgTypes : 쿼리 할 호출 가능 형식에 대한 인수 목록의 형식 #include #include struct S { double operator()(char, int&); float operator()(int) { return 1.0; } }; template typename std::result_of::type f(T& t) { st..

[C++] condition_variable

thread를 수행할 때 때로는 다른 thread의 작업을 기다려야 할 때가 있다. 이때 condition_varialbe을 사용하면 thread를 block 할 수 있다. block 조건은 timeout을 설정할 수 도 다른 thread를 통해 설정할 수도 있다. condition_variable은 다음과 같은 method를 제공한다. notify_one : 해당 조건 변수를 기다리고 있는 thread 중 한 개의 thread를 깨운다. notify_all : 해당 조건 변수를 기다리고 있는 모든 thread를 깨운다. thread는 상기 method 이외에 timeout에 의해서 깨어날 수도 있다. #include #include #include using namespace std; mutex g_m..

[C++] noexcept

C++11부터 throw()가 더 이상 사용되지 않고, noexcept 키워드가 추가되었다. noexcept 키워드는 operator의 형태로, 그리고 specifier의 형태로 제공된다. noexcept() 한정자는 모든 면에서 throw() 보다 강력하고, Stnadard library들을 사용함에 있어, noexcept 한정자는 성능 상의 추가 이득을 제공하기도 한다. noexcept(expression) noexcept 연산자는 컴파일 타임에 해당 표현식이 예외를 던지지 않는 표현식인지 체크하여 표현식이 아래의 경우 중 하나라도 포함한다면 false를 그렇지 않다면 true를 반환한다. 상수 표현식이 아닌 함수가 noexcept 키워드를 가지지 않을 경우 런타임 체크가 필요한 dynamic_cas..

[C++] atomic

std::atomic은 원자성을 보존해주기 위해 사용된다. 다시 말하자면 mutex 없이 두 개의 스레드가 동시에 접근해도 data race 문제가 발생하지 않는다. 또한 std::atomic을 기록하는 라인이 수행될 때는 이전에 나타난 라인들이 수행되어서는 안 된다. std::atomic은 복사와 이동 연산을 지원하지 않는다. 원자성을 보존해야 하기 때문이다. 다행히 복사하는 방법은 있다. atd::atomic y(x.load()); y.store(x.load()); mutex를 통한 전역 변수 동기화에서는 dead lock에 빠질 수 있다. 그래서 atomic을 이용하여 lock, unlock을 사용하지 않고 값을 증가시키거나 감소시킬 수 있는 기능이 C++11부터 제공되고 있다. atomic : a..

[C++] 명시적 링크 (Explcit Linking) 시 GetProcAddress NULL 반환

아래는 mdsn에서 제공하는 dynamic linking 예제이다. 평소에 아무 생각없이 잘 사용하다가 갑자기 GetProcAddress에서 계속해서 NULL이 Return 된다. ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts"); 함수이름도 매개변수 형식도 모두 맞지만 계속해서 NULL이 반환 되었다. 그래서 이것저것 테스트해 본결과 namespace 안에 있는 함수를 가져 오지 못하는 것이었다. 그럼, 함수 이름 앞에 네임스페이스::함수 이렇게 하면 동작할려나.. @_@ 왜 당연히 읽어 올거라고 생각한걸까.. 네임스페이스 안은 완전 다른 세상인데... // A simple program that uses LoadLibrary and // GetProcAd..

전문가를 위한 C++ | 마크 그레고리 | 한빛미디어

이 책은 개정 3판에 사서 본 책이다. 보통의 바이블 서적의 경우 아주 기초적인 것에서부터 자세하게 다룬다. 읽고 있으면 지겨운 부분도 많다. 대부분의 사람들이 집합만 보다가 덮는 수학 책처럼 그런 바이블 서적들이 많았다. 이 책은 앞단에 '전문가를 위한'이라고 명시를 해 두었다. 기초를 어느 정도 다진 프로그래머라면 한 단계 더 발전할 수 있는 계기를 마련할 수 있다. 문법적인 것을 설명하는 것과 더불어 어떻게 구현하는지 왜 그래야 하는지를 세심하게 짚어가며 설명해 준다. 가벼운 내용에 페이지를 허비하지 않으며 꼭 설명해야 하는 부분에서는 여러 장을 들여 설명한다. 개정 3판도 1200페이지가 넘는 엄청난 양이였지만 개정 4판은 1500페이지에 육박한다. 개정 3판은 C++14를 개정 4판은 C++17..

참고자료/도서 2021.07.29

[C++] 3점을 지나는 외접원의 중심점 구하기

3점을 지나는 원은 통상 삼각형의 외접원(CircumCircle)이라고변의 중심에서 내린 수선이 만나는 지점이다. 이때 넓이는 헤론(Heron)의 공식에 의해서 가 된다. 물론, 가정이 있다. 헤론의 공식으로 넓이를 구하면 사인(Sin) 법칙의 응용으로 외접원의 반지름을 구할 수 있다. 그렇다고 원의 중심을 구할 수 있는 것은 아니다. 결국 원의 중심을 구하기 위해서는 각 변의 중심을 잇는 수선을 구해서 교차점을 구해야 한다. // 외접원의 중심 구하기 double d, d2, yi; Point2D[] CenPoint = new Point2D[2]; for (int i = 0; i < 2; i++) CenPoint[i] = new Point2D(); // 각 변의 중심점 구하기 CenPoint[0].x ..

코드/C++ 2021.04.20

컨스트럭터 내에서 할당 대신 초기화를 사용하라

한 번 설정하고, 여러 곳에서 활용하자. 컨스트럭터 내에서 멤버 변수의 설정을 위한 할당 대신 초기화를 사용하면 불필요한 런터임 작업과 타이핑을 줄일 수 있다. 컨스트럭터는 내부적으로 초기화 코드를 만들어낸다. 다음 코드를 보자. class A { string s1_, s2_; public: A() { s1_ = "Hello,"; s2_ = "World"; } }; 실제로는 여러분이 다음과 같이 작성한 것처럼 컨스트럭터의 코드가 만들어진다. A() : s1_(), s2_() { s1_ = "Hello,"; s2_ = "World"; } 즉 직접 초기화하지 않은 개체는 표준 컨스트럭터를 통해 자동으로 초기화되고, 할당 연산자를 통해 할당된다는 것이다. 주요한 개체의 할당 연산자는 이미 만들어진 개체를 다룬..

최소화된 클래스를 사용하라

나누고 정복하라. 작은 클래스가 만들기도 쉽고, 얻기도 쉬울 뿐만 아니라 테스트하고 사용하기도 쉬우며, 다양한 상황에서 활용하기에도 편리하다. 다양한 기능을 가진 클래스 대신 간단한 개념을 담은 작은 클래스를 만들어 활용하자. 하나의 클래스에서 복잡하고 완전한 기능을 제공하는 방식은 분명 매력적인 것이 사실이지만, 작은 클래스를 사용하는 것이 대부분의 시스템에 있어 보다 효율적인 이유가 여러 가지 있다. 최소화된 클래스는 각각 하나의 명확한 개념만을 포함하므로, 여러 개의 분리된 개념을 포함하는 클래스와는 달리 서로 간의 구분이 쉽다는 장점이 있다. 작은 클래스는 보다 이해하기 쉽고, 사용하기 쉬우며 재활용하기도 쉽다. 작은 클래스는 분산과 배치에도 유리하다. 많은 기능이 집적된 클래스의 경우 별도의 덩..

내부의 것은 너무 노출시키지 말라.

클래스가 관리하는 내부 테이터에 대한 핸들을 리턴하여 클라이언트가 개체의 상태를 좌우하게끔 만드는 것은 좋지 않다. 다음 코드를 보자. class Socket { public: ................. int GetHandle() const { return handle_; } // 이렇게 해서는 안된다. private: int handle_; }; 데이터를 숨기는 것은 강력한 추상화와 모듈화의 도구이다. 하지만 데이터를 숨겨놓고 그 제어권을 내주는 것은 스스로를 파괴하는 행동이며, 마치 대문을 잠가놓고 열쇠를 꽂아두는 것과 같다. 그 이유는 다음과 같다. 클라이언트가 기능을 제어할 두 가지 방법을 가지게 된다 클래스의 추상체(Socket)를 이용하거나, 클래스가 의존하고 있는 임플리먼테이션을 제어..

만들고 있는 클래스가 무엇인지 확실히 하라

클래스는 종류에 따라 그 쓰임이 다르며, 적용되는 규칙 또한 다르다. 먼저 값 클래스(std::pair, std::vector)는 다음과 같은 특징이 있다. 값을 중심으로 한 공용 디스트럭터, 복사 컨스트럭터, 할당이 존재한다. 가상 함수가 없다. 기반 클래스가 아닌 구체적인 클래스로 사용된다. 다른 클래스의 직접적인 멤머로서 또는 스택 내에서 인스턴스가 만들어진다. 기반 클래스(base calss)는 클래스 계층을 이루는 단위로, 다음과 같은 특징이 있다. 공용(public)이면서 가상(virtual)이거나 보호된(protected)이면서 가상이 아닌 디스트럭터, 비 공용 복사 컨스트럭터, 할당 연사자 등이 있다. 가상 함수를 통해 인터페이스를 구성한다. 인스턴스는 힙에서 동적으로 만들어지거나 스마트 ..

간접적인 타입 변환을 피하기 위해 오버로딩을 활용하라

간접적인 타입 변환은 코딩의 편리함에는 도움을 줄는지 몰라도 임시 개체가 만들어진다는 점에서 그다지 효율적이지는 못하다. 이러한 추가적인 개체의 생성을 피하고 최적화를 이루기 위해서는 변환이 일어나지 않는 범위 내에서 일반적인 인자 타입을 사용한 오버로딩 함수를 사용하면 된다. 사무실에서 일하던 중 종이가 다 떨어졌다면 어떻게 할 것인가? 복사를 담당하는 동료에게 가서 몇 장을 얻어오면 잠시나마 문제는 해결될 것이지만 그렇게 오래 가지는 못할 것이다. 간접 변환이 하는 일이 바로 이것이다. 임시적인 개체를 만들어 잠지 문제를 해결하는 것을 말한다. class string { string(const char* text); // 간접 변환을 가능하도록 함 }; bool operator==(const stri..

표준적인 형식의 산술 및 할당 연산자를 사용하라

a+b가 있다면 a+=b도 같은 의미인 것이 좋다. 즉 두 대상 사이에 이루어지는 산술 연산자의 경우 같은 효과를 가지는 할당 연산자도 제공해야만 중복을 피하고 효율을 극대화할 수 있다. 일반적으로 바이너리 연산자 @가 있다면 a@=b나 a=a@b와 같은 할당 연산 버전도 준비하고, 같은 의미를 가지게끔 해주는 것이 좋다. 이를 위해서는 다음과 같이 @ 연산을 @= 방식으로 만들면 된다. T& T::operator@=(const T&) { // .... 구현 내용 ... return *this; } T operator@(const T& lhs, const T& rhs) { T temp(lhs); return temp @=rhs; } 두 함수의 기능은 같다고 볼 수 있다. 할당 형식은 실제 작업을 수행하고..

헤더 파일은 충분히 완성된 형태로 만들어라.

각 헤더 파일이 자체적으로 완성도가 있게끔 작성하라. 헤더의 내용과 관련이 있는 다른 헤더는 첨가시켜 주어야 한다. 만약 어떤 헤더 파일이 다른 헤더 파일을 포함시켜야만 작동할 수 있도록 만들어진다면 그만큼 그 헤더 파일의 완성도는 떨어지게 되고, 그 헤더 파일의 사용자는 활용에 어려움을 겪게 될 것이다. 헤더는 스스로 충분히 자급자족할 수 있는 형태로 완성도 있게 만들어야 한다는 것이다. 즉, 빌드 내에서 각 헤더는 분리시켜 컴파일하고, 각각 오류나 경고가 없게 만들어야 한다. 템플릿과 연결되었을 때의 미묘한 이슈들을 짚고 넘어가자. 예 1 : 의존 이름. 템플릿은 정의되는 시점에 컴파일되는 것이 일반적이지만, 의존 이름이나 타입이 아직 그 시점까지 컴파일되지 않았을 경우는 예외이다. template ..

728x90
반응형