const 키워드는 결국 변수의 값이 변경되지 않음을 명시함. 즉, 상수화시킴.


하지만 const 키워드는 정말 다양한 위치에서 사용되기에 혼동이 옴.

크게 변수 선언에 사용되는 위치와 함수 선언에 사용되는 위치 2개로 나뉨.


변수 선언 시

<const> 자료형 <const> 포인터 <const> 변수명;

   (1번)               (2번)               (3번)

함수 선언 시

<const> 자료형 <const> 포인터 함수명(parameter1, parameter2 ...) <const> { }

   (4번)               (5번)                                                             (6번)

변화를 뜻하는 변수에 const 키워드를 붙이는 이유는 그 값이 더이상 바뀌지 않기에 바뀌면 안된다는 것을 명시하는 것.

(어떻게보면 방어적 프로그래밍, 또는 설계의 한 부분이다.)



(2번) 변수 선언 시, 포인터 앞에 또는 이중 포인터 앞에 오는 const




위 그림들을 보면 이제 변수 선언시 const 위치에 따른 의미가 어떤 것인지 알 수 있다.


결국은 일반적인 char, int, long, double 등등의 자료형에 붙는 const와


위의 일반적인 자료형의 포인터에 붙는 const


그리고 일반적인 자료형의 이중포인터에 붙는 const


3개로 나뉜다.


int* const b; 나

int* const* c = &b; 나


결국 묶인 부분은 (int* const) 이고 이는 b의 주소변경을 허락하지 않겠다는 의미이다. c의 주소변경은 상관없다.



하지만 

int* b;

int** const c = &b;


했을 때, const가 의미하는 곳은 int** 부분이다. 그렇기에 이중포인터 타입인 c에 대한 변경만을 허락하지 않는다.

b주소에 대한 변경을 허용한다.



결국 const 선언이 들어간 위치에 따라서 값의 변경을 허용하는 부분이 다르다.


이 부분을 잘 알아두면 나중에 const 위치에 따른 코드의 정확한 의미를 알 수 있을 것 같다.


또한 이 부분을 잘 생각하고 나중에 클래스를 설계할 때 적용하여 const를 통한 좀 더 안정적인 코딩을 하자.



출처: http://tapito.tistory.com/31


const 키워드는 결국 변수의 값이 변경되지 않음을 명시함. 즉, 상수화시킴.


하지만 const 키워드는 정말 다양한 위치에서 사용되기에 혼동이 옴.

크게 변수 선언에 사용되는 위치와 함수 선언에 사용되는 위치 2개로 나뉨.


변수 선언 시

<const> 자료형 <const> 포인터 <const> 변수명;

   (1번)               (2번)               (3번)

함수 선언 시

<const> 자료형 <const> 포인터 함수명(parameter1, parameter2 ...) <const> { }

   (4번)               (5번)                                                             (6번)

변화를 뜻하는 변수에 const 키워드를 붙이는 이유는 그 값이 더이상 바뀌지 않기에 바뀌면 안된다는 것을 명시하는 것.

(어떻게보면 방어적 프로그래밍, 또는 설계의 한 부분이다.)


(1번) 변수 선언시 자료형 앞에 올 때





위 사진들을 유심히 살펴보자. 컴파일러가 컴파일 이전에 오류를 내는 부분이 어디인지 알려준다.

그리고 오류 문구는 Error: expression must be a modifiable lvalue 라는 구문이다.


즉, 상수라서 변경할 수 없다는 뜻이다. 위 구문을 잘 관찰해보면 위 구문이 의미하는 바는 이렇다.


const int a로 선언했다면 a = value의 표현식을 오류로 나타낸다.

const int* b로 선언했다면 *b = value의 표현식을 오류로 나타낸다. (즉, b = address의 표현식은 문제없다.)

const int** c로 선언했다면 **c = value의 표현식을 오류로 나타낸다. (즉, *c = address의 표현식은 문제없다.)


결론적으로 맨 앞에 const의 의미는 변수명이나 포인터에 따른 상수화가 아니다!!


바로 오직 타입(int)에 대한 상수화이다. 


조금 말이 헷갈린데, const int** c로 선언했지만 c의 주소를 바꾸거나, *c 즉 b의 주소를 바꾸는 것은 문제가 안된다.

오직 **c로 접근할 때에만 const 형식에 부딪힌다. 그렇기에 맨 앞의 const의 의미는 포인터나 변수명에 상관없이

int 타입에 대한 상수화가 진행된 것이다. 그래서 위의 예시들도 모두 int값을 변경하려 할 때, 오류를 내보낸다.


결론) 

const int a 든

const int* a 든

const int** a 든


const로 묶인 부분은 int형 뿐이다. 그래서 결국은 이런 표현이 된다.


(const int) a

(const int)* a

(const int)** a



참조: http://tapito.tistory.com/31



동기비동기 방식.


처음으로 클라이언트/서버 프로그래밍을 할 때 수없이 강조받은 내용이다.


클라이언트와 서버 통신을 동기와 비동기 방식 중 어떤 방식으로 할 것인지 결정하는 것.


동기식 서버를 구성할 것인지, 비동기식 서버를 구성할 것인지.


하지만 이 얘기를 들으면서 항상 궁금했다.


뭐가 동기식이고 뭐가 비동기식인지.


둘의 개념을 살펴보고 책을 뒤져보며 이해하려해봤는데 명확히 머리속으로는 그려지지 않았다.


그리고 지금, 지금껏 이해하고 명확하게 된 부분만이라도 정리한다.



한 마디로 말해서, 동기비동기는 A와 B 두 대상이 데이터를 주고 받는 교환하는 방법의 차이이다.



동기식 처리 방법은 A가 B에게 데이터를 요구했을 때, 이 요청에 따른 응답을 주어야만 A가 다시 작업 처리가 가능하다.


Synchronous란 뜻은 '동시에 일어난다'라는 뜻을 가지며, 

여기서 동시에 일어난다는 것은 요청에 따른 응답이 동시에 일어난다는 것을 뜻한다.


Asynchronous란 뜻은 '동시에 일어나지 않는다'라는 뜻을 가지며, 비동기식 처리 방법은

A의 요청에 따른 응답을 B가 즉시 전해주지 않아도, 그 유휴 시간동안 A는 또 다른 작업을 처리 가능한 방식을 의미한다.


여기서 유휴 시간의 존재가 있다고해서 비동기식 처리 방법은 굉장히 느린 것이 아니다. 이 유휴 시간은 요청에 따라

B가 이를 처리하는 과정이 무척 길수도 있겠지만, 대부분 굉장히 짧다. 단지, 연속적인 속성을 지니지 않을 뿐이다.


컴퓨터는 사람에겐 무척이나 짧은 1초동안 자신의 CPU 헤르츠만큼 작업을 수행할 수 있다.

그렇기에 1초, 아니면 1초보다 더 짧게 내지는 더 긴 시간을 아무 행동없이 보내는 것은 컴퓨터 활용에서 굉장히 아쉽다.


이런 시간들을 사용하여 좀 더 유연하고 효율적인 작업을 하는 방식을 비동기식 방식이라고 하며,

오직 하나의 작업에만 충실하여, 이 작업 이외엔 컴퓨터를 활용하지 않는다면 동기식 방식이라고 한다.


이 개념은 소켓 네트워크에서 블로킹과 논블로킹 방식과도 매우 유사하다.



하지만 언제나 이런 개념을 알아도 막상 하나의 게임이나 서비스를 생각하면서 이 클라이언트/서버 구조가

비동기 방식인지, 동기 방식인지 떠올리기는 어렵다.



그럴때면, 한 시점에 반드시 A와 B의 데이터가 반드시 일치해야 하는 경우를 살핀다.

일치하지 않았을 경우 정말정말 치명적인 상황.


바로 은행 계좌 처리이다. 한 사람이 ATM기기에서 돈을 출금했는데, 그 계좌 잔고의 변화가 즉각 갱신이 일어나지 않으면

이것이 조금씩 커져 결국 전체 시스템의 문제로 발생한다. (절대 그럴 일 없겠지만, 이렇게되면 그 은행은 아마 망할 것 같다.)


확실한 것은 이 글을 쓰고있는 나도 아직 명확하게 감이 안잡힌다. 아니 애초에 정답이란게 있는 부분인가.


서버를 동기/비동기 둘 중에 하나를 선택하라고 했지만, 은행을 제외한 대부분의 서비스는 비동기라고 생각한다.


왜냐하면 만약 동기 서버라면 클라이언트 A가 요청을 보내기 전까진 그 서버는 멈춘채 클라이언트 A의 요청을 기다린다.

하지만 실제 서버에 연결된 클라이언트는 A만 있는 것이 아니라 적게는 수 백명 부터 많게는 수 천, 수 만명까지. 서버는

여러 클라이언트의 요청을 동시에 처리해야 하는 서비스를 가진다.


그렇기에 단순히 클라이언트 A 하나만의 동기화가 아닌 여러 클라이언트의 작업을 처리할 수 있어야 한다. 그래서 대부분의

서버는 비동기식 서버라고 생각은 하지만!!!


이 부분이다!

항상 헷갈리는 부분. 

은행 계좌와 마찬가지로 게임이나 서비스로 치면 그 컨텐츠의 크리티컬한 요소는 반드시 데이터 동기화가 이루어져야 한다. 

그렇지 않다면 그 서비스는 망할테니까.


분명 수 많은 클라이언트들의 접속을 유지하기 위해선 구성은 비동기식으로 해야할 텐데, 그 작업의 갱신은 동기화가 이루어

져야 한다.


???


뭘까 도대체. 놓치고 있는 부분이.


비동기식 서버 안에서 새롭게 동기화 시키는 부분이 필요한걸까, 물론 필요하겠지. 그럼 그 방식이 동기식 서버랑은 

관련이 없는 내용일까? 아니면 비동기식 서버 틀안에서 동기식 서버로 구성된 부분이 있는 걸까. 혼재된걸까?


분명 쓰기 전까지만 해도 뭔가 명료해서 작성하고 있었는데, 쓰다보니 다시 의문이다.


역시 이 부분은 직접 동기식과 비동기식 서버를 구성해서 비교해보지 않는 이상 이론만으로는 풀리지 않을 것 같다.


그래서 나중에 정말 다시 정리되면 새로 쓰기로하고 제목도 수정했다.





스마트포인터객체다.


일반적인 포인터가 변수라면 스마트포인터는 객체로 나타낸다. 


포인터에 스마트라는 단어가 접목된 이유는 스마트포인터를 사용하면 2가지의 큰 이점이 있다.


1. 버그 예방

2. 코드 길이 감소


두 이점 중에서 중요하지 않은 것이 없다.


그리고 버그 예방이라는 측면에서 먼저 봐야할 것은 이렇다.


C/C++언어에서 발생하는 대표적인 오류 케이스는 다음과 같다.

1. 메모리 누수

2. 할당 실패

3. Dangling 포인터


스마트포인터는 이 3가지 경우에 관련된 버그등을 예방하고 일반 포인터를 사용할 경우 이런 예방 처리를 해야 할

코드를 줄임으로서 전체적인 코드 길이가 줄어들어 그 명료함과 가독성역시 뛰어나진다.


먼저 맨 앞에 기술했듯이 스마트포인터는 객체이다. 

객체이기 때문에 생성자와 소멸자를 가진다.


생성자와 소멸자가 있기 때문에 포인터를 사용할 때 반드시 작성해야 할 방어적 프로그래밍인 초기화와 해제를 

프로그래머가 해줄 필요없이 자동으로 이 부분들을 처리해준다.


그렇기에 메모리 할당 후 처리가 끝난 후에 해제가 되지 않아 일어나는 '메모리 누수' 현상과

이미 메모리에서 해제된 주소를 가리키는 현상인 'Dangling 포인터' 현상을 일어나지 않게 만든다.



결론적으로 스마트포인터는 C++코딩에서 더욱 안전하고 더욱 효율적인 코드를 작성하게 해준다.


이를 사용하고 더욱 완벽한 이해를 위해선 Alexandrescu가 집필한 Modern C++ Design의 스마트포인터 챕터를 읽어보자.



*정말 잊지말아야 할 부분: 스마트포인터는 Garbage Collector가 없는 C/C++언어에서 메모리 해제를 담당.


출처: http://ootips.org/yonat/4dev/smart-pointers.html



+ Recent posts