여러 쓰레드를 사용할 때 아무 생각 없이 static 변수를 사용하면 안된다고 한다.

같은 작업을 할 경우에는 쓰레드들이 해당 변수를 다 같이 사용할 수 있기 때문에

결론적으로 망해버린다.


__declspec(thread) static int a

와 같이 사용할 경우, 쓰레드 '마다' 각각의 정적 변수를 가지게 되서

작업 상황을 유지할 수 있고 , 꼬이지도 않게 된다고 한다.

 

Posted by GENESIS8

댓글을 달아 주세요


플래그를 사용하기에 편리한 비트 연산자에 대해서 기록..



~ (NOT)

비트를 반전시킨다.

ex) 0000  -> 1111


& (AND)

대응되는 비트가 모두 1  1이다.

ex) 1111

       0101

 ㅡㅡㅡㅡ

       0101 (비교한 둘이 모두 1인 경우에만 남긴다.)



| (OR)

대응되는 비트가 모두 0  0이다.

ex) 1111

       0101

 ㅡㅡㅡㅡ

       1111 (둘 중 하나라도 1이면 1이다.)



^ (XOR)

 개의 비트가 달라야 1이다.

ex) 1110

       0100

 ㅡㅡㅡㅡ

       1010 (같으면 거짓이라는 변태같은 규칙)


Shift 연산

<<

지정한 수만큼 왼쪽으로 비트들을 이동시킨다.

ex) 0000 1110에 대하여 << 2  수행시.. 0011 1000


>>

지정한 수만큼 오른쪽으로 비트들을 이동시킨다.

ex) 0000 1110에 대하여 >> 2  수행시.. 0000 0011

// 1 하나는 날아가버렸다. 0.5 를 저장하는 일은 없다.









Posted by GENESIS8

댓글을 달아 주세요

반복자 무효화란?
반복자가 가리킨 대상을 erase 하여 삭제하였을 때. 일어나는 문제 현상을 말한다.

예시 )
iterator i;
m_object.erase(i);

반복자 무효화 현상을 설명하자면 다음과 같다.

반복자는 포인터를 포함한 객체에 불과하므로 본질적으로는 포인터의 기능을 수행한다.
문제를 단순하게 접근하여, 포인터가 특정 메모리의 요소중 하나를 가리키고 있다가.. 해당 메모리에서 그 요소가 삭제되면?.. 

연결 리스트의 노드 구조를 생각해보자. 노드 구조는 하나의 노드가 다른 노드로 연결 될 수 있는 길 (포인터)을 가지고 있었는데.. 그게 날아가버렸다면?

그것을 따라 길을 타고다니던 반복자의 입장에서는 다음으로 어딜 가야할 지 알 수 없다.


그럼 배열과 같은 연속적인 메모리 구조를 생각해보자.

memcpy의 문제를 생각하면 데이터를 원본 안에서 다루는 구조일 것이라고는 도저히 생각되지 않는다. 그렇다면 데이터는 경우에 따라 얼마든지 이동할 것이고.. 이 때 해제되어 폐허만 남았을 메모리를 가리키는 반복자는 또 바보가 된다.


따라서 반복자는 

iterator i;
m_object.erase(i++);

이처럼 삭제할 대상을 삭제한 후, 자신의 자리를 새로 잡아주어야한다. 이 경우 날아가게 될 데이터를 전달한 후에 자신은 그 다음이라는 곳으로 이동하기 때문에 문제가 생기지 않는다.



Posted by GENESIS8

댓글을 달아 주세요

RTTI

프로그래밍/C, C++ 2015. 3. 31. 07:07


RTTI (runtime type information)RTTI는 C++ 컴파일러 내에 포함되어 있는 기능으로서, 객체의 유형을 실행 시에 결정할 수 있도록 허용한다. C++이나 다른 고급언어의 컴파일러에서 가지고 있는 이 기능은, 메모리 상주 객체에 유형 정보를 추가한다. 이렇게 함으로써, 실행 시스템은 객체의 캐스트가 유효한 것인지를 확실히 하기 위해, 그 객체가 특정 유형인지를 결정할 수 있다. 객체 기술의 기본 원리 중 하나가, 실행시 객체를 동적으로 변화시킬 수 있는 능력인 polymorphism이다. 


 

RTTI 의 목적

 

하나의 공통 기초 클래스로부터 상속된 클래스 계층 존재 가정.
이 클래스 계층에 속해 있는 클래스들의 어떤 객체를 기초 클래스 포인터가 지시하도록 설정 가능. 어떤 정보를 처리한 후 이들 클래스들 중에서 어느 하나를 선택하고,
그 클래스형의 한 객체를 생성하고, 기초 클래스 포인터에 대입하기 위해 그 객체의 주소를 리턴하는 함수를 호출.
그 포인터가 지시하는 객체의 종류가 무엇인지 어떻게 알 수 있을까?

어떤 클래스 메서드의 정확한 버전을 호출하고 싶기 때문에 데이터형을 알고 싶을 수도 있음.
그러한 경우 그 함수가 클래스 계층의 모든 멤버들에 의해 처리되는 가상 함수라면, 굳이 그 객체형을 알 필요는 없음. 그러나 파생 객체가 상속되지 않은 메서드를 가지고 있을 수도 있고, 일부 객체들만이 그 메서드를 사용할 수도 있음. 또는 디버깅 목적으로, 어떤 종류의 객체들이 생성되는지 추적하고 싶을 수도 있음.

 

1. dynamic_cast 연산자는, 가장 많이 사용.
포인터가 지시하는 객체형이 무엇인지 알려 주지 않음. 대신 그 객체의 주소를 특정형의 포인터에 안전하게 대입할 수 있는지 알려 줌.

가능하다면, 기초 클래스형을 지시하는 포인터로부터 파생 클래스형을 지시하는 포인터를 생성. 반면에 가능하지 않다면, 널 포인터인 0을 리턴.


2. typeid 연산자는,
두 객체의 데이터형이 같은지 결정 가능.
어떤 객체의 정확히 데이터형을 식별하는 하나의 값을 리턴.

- 클래스의 이름
- 객체로 평가되는 식

typeid 연산자는 type_info 객체에 대한 참조를 리턴.

 

3. type_info 구조체는,
어떤 특별한 데이터형에 대한 정보를 저장.

typeinfo(이전의 typeinfo.h) 헤더 파일에 정의되어 있는 클래스.
이 클래스는 데이터혀을 비교하는데 사용할 수 있도록 == 와 != 연산자 오버로딩.

ex.
typeid(Magnificent) == typeid(*pg)

pg가 널 포인터이면, bad_typeid 예외 발생

 

 

* RTTI 는 가상 함수들을 가지고 있는 클래스들에 대해서만 사용 가능.
  그들이 파생 객체들의 주소를 기초 클래스 포인터들에 대입해야 하는 유일한 클래스 계층 때문.

 

우선, 설사 typeid로 dynamic_cast가 할 수 있는 모든 걸 할 수 있다고 해도, 반대로 typeid가 할 수 있는건 dynamic_cast로도 할 수 있기 때문에 dynamic_cast를 어따쓰냐는 질문은 'dynamic_cast를 쓰면 typeid를 쓸 필요가 없죠. 그럼 typeid는 뭐에쓰나요?' 라는 질문과 가치가 같습니다.
한쪽으로 다른 쪽을 할 수 있다고 해서 다른 쪽이 쓸모 없어지는 건 아닙니다. 더 편리한 방법이 있다면 그걸 쓸 수도 있겠죠.
typeid로 일일이 타입을 체크한 후에 static_cast로 캐스팅하는 것보다는 dynamic_cast로 캐스팅하는게 훨씬 깔끔하고 직관적일 수 있습니다.
memcpy가 있는데 왜 strcpy를 쓸까요? strcpy가 있는데 왜 strdup를 쓸까요? 생각해보시기 바랍니다.
더 나아가 typeid로 체크하고 static_cast로 캐스팅하게 되면 같은 변수/타입을 여러번 적어줘야하는데(bp의 typeid를 비교한 후에 bp에 대입), 같은 내용을 중복 적재하다보면 실수할 확률도 높아지죠. 예를 들면 foo()안에서 if 조건안의 대입문이 뒤바뀌는 실수를 할 수도 있습니다(bp의 typeid를 비교한 후에 cp에 대입하는 실수).



A - B, A - C 가 아니라 A - B - C 라고 합시다.
그리고 원하는 바가 B 객체이거나 B 의 파생객체인지 확인하기 위해서 typeid 를 쓰고자 하신다면 B, C 둘 다 확인해봐야 합니다.
만일 상속구조가 늘어나면 비교대상은 계속해서 늘어나게 됩니다.
dynamic_cast 를 쓴다면 B 로 casting 한번만 해보면 됩니다. dynamic_cast 는 객체의 부모 class 를 따라가면서 확인하는 과정을 거칩니다.
즉 객체의 class 가 C 였다면 C - B - A 순서로 올라가면서 casting 이 가능한지 조사해봅니다. 이 경우는 B 에서 멈추겠죠.
그래서 dynamic_cast 는 매우 느려질 수 있습니다.
typeid 로 가능한 요구사항 즉 단순히 정확한 비교 하나를 원하시는 거라면 typeid 쓰시는게 좋죠. 그리고 그 후 casting 이 필요하다면 static_cast 를 쓰는 것은 상당히 바람직합니다.
그러나 dynamic_cast 를 쓴다고 그리 느려지는 것도 아닐 겁니다. Compiler 구현을 그리 멍청하게 하지는 않았을테니까요.
다만 초기 Visual C++ 의 dynamic_cast 는 매우 느렸다고 하더군요. RTTI 기능을 끌 수 있게 한 이유 중 하나였을 겁니다.


- 내용 출처

soen.kr

https://kldp.org/node/141614

http://softwareji.tistory.com/107



Posted by GENESIS8

댓글을 달아 주세요

  1. ㅇㅇ 2021.05.23 06:08  댓글주소  수정/삭제  댓글쓰기

    dynamic_cast를 쓰면 typeid는 안써도 되는거죠?


설명 -

C++에서 새로이 지원하게 된 명시적 캐스트 연산자들이다.



기능 및 특징 -


const_cast

클래스에서 const, volatile 및 __unaligned 특성을 제거합니다. 라고 msdn에 쓰여있다.

 

static_cast

명시적 형 변환을 위한 캐스트 연산자.


dynamic_cast

포인터나 레퍼런스를 기본 클래스-> 파생 클래스로의 다운 캐스팅과, 다중 상속에서 클래스 간의 안전한 타입 캐스팅에 사용된다. 안전하지만 느리다. 이 연산자를 사용하려면 '하나 이상의 virtual 함수'가 존재해야한다.


reinterpret_cast

타입이니 뭐니 하는 것을 따지지 않고 무조건적으로 변환해버린다. (reinterpret 다시 해석하다, 새로 해석하다) 대단히 위험한 방법으로, 안전하다는 보장이 없다.



사용 방법 예시 및 이해도 -


const_cast

클래스에서 const, volatile 및 __unaligned 특성을 제거합니다. 라고 msdn에 쓰여있다.



이런 소소한 사용도 가능하다.




http://prostars.net/53

이 곳의 글을 읽는 것이 좋은듯 하다.



static_cast

static_cast<int>(변수명);과 같이 사용한다.



자식 타입으로 부모 객체를 대입받으려 하면 컴파일러가 변환할 수 없다며 오류를 띄운다.

이때 static_cast를 사용해주면 변환이 되는데..



C형 명시적 캐스팅이면 끝난다.

그럼 대체 static_cast는 왜 쓰는 걸까?




char형에게 int형을 할당받게 하려는 문제를 C형 캐스팅은 그냥 넘어가버렸다. 그러나 static_cast는 곧장 오류를 띄워 잘못된 변환임을 알렸다.


이처럼 사용자의 몰지각한 변환을 막아주는 안전장치 역할을 한다.
static_cast는 C 스타일의 명시적 캐스팅처럼 명시적일 뿐더러, '안전' 하다.




dynamic_cast

dynamic_cast<int>(변수명);과 같이 사용한다.



방금 전 static_cast 예제때. 캐스팅하려면 static 혹은 dynamic 캐스트 연산자를 쓰라고 했었다. 그래서 한번 사용해보자!


결과는 에러!?



해당 클래스가 '다형 형식' 이 아니라고 난리를 친다.

그럼 이 다형 형식이란 건 뭘까?


위에서 . 이 연산자를 사용하려면 '하나 이상의 virtual 함수'가 존재해야한다. 라고 설명했었다. 바로 그것이 다형형식이다. virtual 함수. 즉 가상 함수는 오버라이딩을 통해 '다형성'을 구축한다. 자 그럼 virtual 함수를 만들어보자.



함수 하나 생겼을 뿐인데, 정상적으로 작동한다.

사실 이는 dynamic_cast가 상속관계에서 사용하기 위해 만들어진 연산자이므로 당연하다.


그런데, 이것이 정상적으로 작동하는 것일까?


dynamic_cast가 캐스팅해주는 것은, '객체를 읽어들이는' 포인터나 참조자의 타입을 다운 캐스팅하는 것이지.. 객체를 변환하는 것이 아니다.



자 이게 무슨 소리인지 확인해보도록하자.


dynamic_cast는 '변환이 잘못된 경우'에 NULL을 던진다.


실제로.. 내용을 실행해보면 함수 대신에 오류가 반겨준다.





이는 C형 명시적 캐스팅을 한 것과는 뭔가 판이하게 다른 상황이다.

C 형으로 명시적 캐스팅을 하면 이와 같다.





무척 잘 돌아간다. 그렇다면 대체 왜 dynamic_cast를 써야하는 지 애매해진다.



만약 '부모 타입의 포인터'로 '자식 객체'를 가리키고 있다가. 그것을 '자식 타입의 포인터'가 받게 하면 어떻게 될까?




이처럼 에러가 난다. 이 럴때 사용해주면?





reinterpret_cast

사용법은 위의 다른 함수와 다르지 않다.



하지만 retinerpret_cast는 마치, 홈쇼핑에서 광고하는 만능 물건들 같다. 만능 ~~ 이 본드만 있으면 모든 게 척척.. 하는 식으로 말이다. 각설하고 내용을 보자.




int a에, double의 포인터를 대입하거나 혹은 그 반대는 누가 보아도 비 정상적이다. int와 double형 사이의 변환이라면 약간의 데이터 손실을 포함해도 정상참작의 여지가 있지만 이건 전혀없다!


그런데 reinterpret_cast는 된다. 상관도 하지 않는다!


이게 무슨 신박한 일인가 하면....

reinterpret_cast를 사용하면, 데이터를 비트 단위로 그대로 때려넣게 된다.





포인터 안에 들어 있느 값을 정수로출력했더니 int a의 값과 똑같은 값이 나온다.


하지만.. reinterpret_cast는 무척 안전하지 않은데,


그것은 당장 %d 출력인 b를, %d , *b로 만 바꾸어보아도 알 수 있다. 실행하자마자 컴파일러가 오류를 일으키는 것을 볼 수 있다.



장단점 및 비교 -

장단점이라고 이거다하고 찝어서 말하기가 애매하다.


첨부 자료 -



C 캐스팅.zip




참고한 주소 및 정보 - 

// 좋은 블로그. 꼭 가보길 권장

http://prostars.net/55


Posted by GENESIS8

댓글을 달아 주세요


설명 -

virtual 키워드는 함수에 붙일 수 있다. 이 키워드를 붙이는 의미는 가상 테이블(virtual table)을 작성하기 위해서다. 이를 통해서 오버라이딩이 가능해진다.


기능 및 특징 -

오버라이딩이 가능해진다. 앞뒤 다 빼먹고 이게 뜬금없이 무슨 소린가 하겠지만, 상속관계도에서 오버라이딩을 하기 위해서는 가상 함수여야한다.


먼저 객체는 생성되었을 때 자기 자신의 멤버를 가리키고 있다. 만약 부모의 객체를 자식을 가리킨다면 어떨까? 부모 포인터가 자식을 가리켜도 객체 자체는 자식이니까 우리는 자식을 원활하게 쓸 수 있을까?

 

정답은 불가능 이다. 

 

이런 것이 뭐가 중요할까 싶지만... RTS 게임을 구현하여서 유닛이 100종류 정도 있다. 물론 각각의 공격 방식이나 형태 등은 전부 다를 것이므로, 우리가 '공격' 명령을 내렸을 때 유닛이 취할 행동은 제각각 일 것이다.

 

그렇다면 우리는 100 종류의 유닛에 대하여 100종류의 호출을 해주어야할까? 단순히 사용자가 어택 을 누르면 전부 다?

 

 

위의 질문으로 돌아가보자, 부모가 자식을 가리켜 '자식에서 새롭게 정의된 기능'을 쓸 수 있다면 저런 바보같은 행동은 필요하지 않다. 모든 유닛이 부모로부터 '공격'을 상속받게 하고 부모 타입으로 죄다 받아서 공격 명령을 내리면 각각이 자기 자신에 맞는 공격을 행하게 되는 것이다.

 

이를 다형성이라고 하며, virtual 키워드는 오버라이딩을 성립할 수 있게 해주어 다형성을 구현하는 핵심 역할을 한다. 이 과정에서 가상 함수 포인터(virtual function pointer)가 생겨난다.


 

사용 방법 예시 및 이해도 -

 

 

이처럼 접근하면...

 

 

 

 

 

 

 

 

 

 전부 조상이 나와버린다.

 

 

 

그러나 virtual 키워드를 붙이면 결과가 다르다.

 

 

 

 


 

 

 

 


 

그렇다면 왜 이러한 결과가 나오는 것일까?

 

 

 

이 상황을 보다 명시적으로 보기 위해서 내부의 소스(자신의 주소를 표기하도록)를 아래와 같이 수정하였다. 그리고 돌려보았다.

 

 

 

 

 

분명 this의 주소는 계속해서 변하고 있다. 즉 객체 자신을 의미하는 this 포인터는 전부 다르다는 의미인데? 문제는 3번을 타는 동안 계속해서 super를 타고 있다.

 

결과 :

 

 

이럴수가. 전부 함수의 주소가 같다.

 

 

우리는 여기서 '정적 바인딩'과 '동적 바인딩'의 개념을 상기해야한다.

 

 

컴파일러는 함수가 어떤 주소에 있는지 알고 있으며 그래서 호출문을 이 함수의 주소로 점프하는 코드로 번역할 것이다.

 

컴파일하는 시점(정확하게는 링크 시점)에 호출 주소가 결정되는 것을 정적 결합[정적 바인딩](Static Binding) 또는 이른 결합(Early Binding)이라고 한다. 결합(Binding)이란 함수 호출문에 대해 실제 호출될 함수의 번지를 결정하는 것. 일반적인 함수들은 모두 정적 결합이다.

 

바인딩은 다른 함수만이 아니라 컴파일 전반 사용되는데 이에 대해서는 본 블로그의 게시글 '바인딩'에 기록하였.

 

모두 정적 결합이다.. 따라서 지금의 상황이 일어난 것이다. super의 print는 처음에 '정적바인딩 되어 기록된 002510E1'이다. 그렇기 때문에 super의 입장에서는 print == 002510E1 이라고 생각한다. 객체가 무엇이건 print는 002510E1 주소로만 가면 되기 때문에.. 부모 , 자식의 print가 호출될 하등의 이유가 없는 것이다!

 

 

 

그럼 이번에는 virtual을 사용한 경우를 보도록 하자.

 

바로 결론부터 보자.

 

 

그런데.. 결론은 다르지만 주소는 같지 않은가?

뭔가 잘못 된 것이 아닌가 싶지만.. 잘못되지 않았다. 위의 주소는 정적 바인딩된 주소일 뿐이다.

 

이게 무슨 소리냐면.. 가상 함수는 '동적 바인딩' 된다.

 

가상 함수를 소유한 클래스는 가상 함수 테이블(vftable)을 가리키는 4바이트의 가상 함수 포인터(vfptr)을 가지게 된다. 이 것의 존재 여부에 대해서는 함수를 하나 만들어둔 클래스와, 가상 함수를 하나 만들어둔 클래스 간의 size 비교를 통해서도 알 수 있다.

(그냥 함수인 곳은 1바이트 , 가상 함수 측은 4바이트가 나올 것이다. 자세한 내용은 EBCO를 참조.)

 

동적 바인딩이란, 동적 시간대(Runtime)에 결합 되는 것을 말하는 데. 현재의 상황의 경우, 처음부터 함수의 주소를 결정해놓고 호출하는 것이 아니라, 호출 시에 함수의 주소를 알려주고 있는 상황이 된다. 아래의 예제를 보자.

 

 

 

 

 

 

 

 

 

각 vfptr이 가리키고 있는 곳이 다르지 않은가? 그렇다. 동적 바인딩은 이처럼 함수에 대해서 저장된 포인터를 써서 가리키는 방법인 것이다.

 

그로 인해 우리는 각 객체의 가상 함수 포인터(vfptr)에 맞는 함수를 호출 하는 것이 가능해졌다!

 

 

덧붙여 memset을 배운 사람이라면.. 가상 함수가 있는 클래스 / 구조체에는 memset을 사용하지 마라.. 라는 이야기를 들어보았을 것이다. 이유는 아래와 같다.

 

 

 

 

이 때문에 memset은 가상 함수를 보유한 클래스에 사용하면 안된다.

 

 

덧붙여 업 캐스팅 후 해제할 때의 문제를 해결할 수도 있다.

부모가 자식을 가리키고 있는 경우, 그대로 해제하면 부모의 범위만 해제되는 문제가 있다.

virtual 키워드를 사용하여 이 문제를 해결할 수 있다.

 

 

 

 

 

 


 

장단점 및 비교 -

단점

1. 클래스 크기에 4바이트가 더 들어간다. (가상 함수 포인터)

2. 내부에서 체크를 해야하므로 조금이라도 더 느려지긴 느려진다.

3. memset등의 전체 메모리 초기화 함수를 사용할 수 없다.
장점
오버라이딩을 가능하게 한다.

 

첨부 자료 -

 

 

오버라이딩.cpp

 


 

참고한 주소 및 정보 -

// 정적 바인딩 , 동적 바인딩에 대하여

soen.kr
http://secretroute.tistory.com/entry/140819

Posted by GENESIS8

댓글을 달아 주세요


C 표준 동적할당 함수인 alloc 시리즈와 (malloc , calloc , realloc)

C++ 표준 동적할당 '연산자'인 new delete의 주된 차이는 '생성자와 소멸자'의 호출 여부다.


memset을 활용하는 것 처럼, void* 형으로 다수의 동적 할당을 받을 포인터들을 정리할 수 있는데, 이와같이 delete 할 경우에는 소멸자가 호출 되지 않는 문제점이 존재한다.


 

 

 

 

 



 

newDelete테스트.cpp

 

Posted by GENESIS8

댓글을 달아 주세요

MSDN 해석(VS2013)


1. __inline, __forceinline, inline 개요

https://msdn.microsoft.com/ko-kr/library/z8y1yy88.aspx


정의

inline 및 __inline 지정자는 함수가 호출되는 모든 위치에 함수 본문을 치환하도록 컴파일러에게 지시하는 것이다.


inline function_declarator;   
__inline function_declarator;   // Microsoft Specific
__forceinline function_declarator;   // Microsoft Specific


설명

inline은 컴파일러의 비용 대 효과 분석을 통해 이익이 있다고 판단할 때만 발생한다. 함수를 호출하는 오버헤드를 경감할 수 있지만, 코드 사이즈 크기가 커지는 잠재적인 코스트가 존재한다.


__forceinline 키워드를 사용하면, 컴파일러가 행하는 비용/이익 분석 대신에 프로그래머의 판단에 의존한다.

__forceinline을 사용할 때 특별히 주의해야 하는데, 이는 무분별하게 사용할 경우

코드는 커지고 퍼포먼스(성능) 향상은 미미할 수 있으며 경우에 따라서는(inline한 코드가 큰 경우) 페이징이 증가되는 등의 이유로 성능이 떨어질 수 있다.


inline 키워드를 사용해도 반드시 함수가 인라인되는 것은 아니다.

__forceinline 키워드를 사용하는 경우에도 특정 함수를 강제로 인라인 할 수 없는 경우가 있다.

/clr 옵션으로 컴파일을 하는 경우, 함수에 적용하는 보안 속성이 있다면 이 함수는 인라인하지 않는다.


inline 키워드는 C++에서만 사용할 수 있다. __inline 및 __forceinline 키워드는 C/C++에서 모두 사용할 수 있다.

이전 버전과 호환성을 위해 _inline과 __inline은 동의어로 사용된다.


2. __forceinline 키워드로 인라인 할 수 없는 경우

- 함수 또는 호출대상이 /Ob0(디버그 빌드 기본값) 컴파일 옵션으로 컴파일 된 경우

- 함수 또는 호출대상이 서로 다른 형식의 예외 처리를 사용하는 경우

(예 : 한쪽은 C++ 예외처리, 다른쪽은 구조화된 예외처리를 사용하는 경우)

- 함수가 가변인수 리스트를 가지고 있는 경우

- 함수가 /Og, /Ox, /O1 또는 /O2를 쓰지 않고 인라인 어셈블리를 사용하는 경우

- 함수가 재귀적이고 #pragma inline_recursion(on)을 하지 않은 경우. 

Pragma 재귀함수는 총 16번의 깊이로 인라인한다. 깊이를 조절하려면 #pragma inline_depth 를 사용하면 된다.

- 함수가 virtual이고 가상적으로 호출되는 경우, 가상함수의 직접호출은 인라인 가능.

- 프로그램에서 해당 함수의 주소를 사용하는 함수 포인터로 호출될 경우. 

주소가 있었던 해당 함수에 대한 직접 호출의 경우 인라인 가능.

- naked_declspec로 수식된 함수의 경우.




Posted by GENESIS8

댓글을 달아 주세요


설명 -


string은 기본 타입 char를 토대로 보완과 추가를 통해 만들어진 '문자열' 관리를 위한 표준 클래스다.


문자열을 편하게 관리할 수 있다. 기존 배열은 메모리의 낭비 혹은 크기의 확장에 의한 문제 등을 걱정했어야 했었다. 반면 포인터는 문자열 복사에 대응하지 못했고, 둘을 혼용해서 쓰는 것도 불편할 뿐더러.. 문자열을 위해 지원하는 string 함수들은 _s(secure) 버전에 들어서 사용 조건이 무척 불편하게 되거나 (인자를 4개씩 받아 처먹는다), 사용을 위한 제반 조건 (포인터를 괜시리 생성해서 또 고민해야한다) 따위가 따르는 문제가 있었다.


헌데 string은 이러한 모든 문제를 해결해준다!


기능 및 특징 -


string은 문자열을 관리하는 클래스다. 부언할 것 없이 문자열하면 무엇인지 감이 팍 올 것이다. string 클래스의 기본적인 특징은 아래와 같다.


특징 1.

string str = "test dest best";
printf_s("%s 크기 : %d\n",str.c_str() , str.capacity());
str += "ㅋㅋㅋ ㅋㅋㅋ ㅋㅋㅋ";
printf_s("%s 크기 : %d\n",str.c_str() , str.capacity());



capacity를 통해서 크기를 조사해보니.. 필요에 따라서 공간의 크기가 확장된다. 즉 메모리 공간을 가변적으로 차지하는 자료형이라고 할 수 있다.



특징 2.


==나 < 등의 연산자를 통한 비교가 가능 할 뿐더러 = , += 등의 연산자를 사용하여 값을 대입 / 추가하는 것이 가능하다. strcat, strcmp등을 사용하지 않고 복사와 대입은 물론, 비교까지 가능하게 된 것이다.




특징 3.


string 객체의 함수를 사용하여 c시절 string 헤더에서 존재했던 문자열 함수를 사용할 수가 있다. 비슷한 기능을 하지만 이름이 바뀌거나, 새로이 추가된 함수도 존재한다.


사용 방법 예시 및 이해도 -

string st; 혹은 string test = "qweqwe"; 와 같이 string 클래스의 객체를 선언하고 사용하면 된다. 단 c++에서 부터 지원된다. c에서는 지원하지 않는다.


장단점 및 심화비교 -

물론 장점만 있는 것은 아니다.. string에 대응하지 않는 클래스도 분명히 있으며, 과거부터 만들어서 주로 사용되지만 표준은 아니거나, 이미 개선된 버전이 존재하는 함수들에 대한 호환이 안된다. 물론 스트링에서는 이를 위해서 c_str()이라는 (char* 문자열로 반환하는) 함수를 지원하고 있다. 또한 char에 비하면 느리다.


첨부 자료 -


string 클래스를 어느정도 작성해보았다. 안타깝게도 이터레이터는 없다.


G_string.zip



참고한 주소 및 정보 - 

http://blog.naver.com/medicant

http://slowlywalk1993.tistory.com/entry/C-String-Class

http://itguru.tistory.com/198



Posted by GENESIS8

댓글을 달아 주세요

설명 -

friend 키워드는 c++에서 지원하는 예외적인 기능의 키워드다. 접근 지정자(Access Modifier)를 완벽히 무시할 수 있는 예외적인 기능을 가졌다. 객체 지향 개념의 정보 은닉(Information Hiding) 개념에 정면으로 위배된다.


기능 및 특징 - 

private 건 protected건 friend로 선언된 대상에게는 완벽하게 public으로 작용한다. 대상이 외부이건, 상속 관계도에 있건 그런 것은 중요치 않다.


friend 키워드는 특이하게도 '당하는' 쪽에서 선언한다. 


기존의 키워드 선언은 그것을 하려는 쪽에서 붙였었다. ex) static 선언시 해당 대상은 static 멤버가 된다. 반면 friend는 friend로 지정될 대상을 정하고, 그 내용을 자기 클래스 안 (혹은 함수) 에 선언한다.


 1. friend 지정은 단 방향이며 명시적으로 지정한 대상만 friend가 된다.
 2. friend 지정은 전이되지 않으며 friend의 friend 관계는 인정하지 않는다.
 3. 복수의 대상에 대해 동시에 friend를 지정할 수 있지만 한 번에 하나씩만 가능하다.
 4. friend 관계는 상속되지 않는다.


1번 - > 키워드를 선언한 객체에 대해서 선언 받은 대상은 얼마든지 접근할 수 있지만, 반대로 선언 받은 대상에 대해서 선언한 객체는 전혀 접근할 수 없다. ex) A가 B를 friend로 선언했다면, B는 A를 멋대로 쓸 수 있지만 A는 B에게 접근할 수 없다.

물론 friend 키워드는 서로 사용할 수 있으므로 A와 B가 서로 friend로 등록하면 A와 B 서로가 접근하는 것이 가능하다.


2번 , 4번 - > A가 B를 friend로 선언했어도, B의 friend인 C가 A를 건드릴 순 없다. 이는 상속관계에서도 마찬가지이다.


3번 - >  여러 객체에 대해 friend 선언할 수 있다. 다만 int a, b , c; 같은 선언은 지원 안함.


사용 방법 예시 및 이해도 -


friend 키워드를 사용하는 방안은 3가지다.

1. friend 클래스

2. friend 멤버 함수

3. friend 전역 함수


1. friend 클래스


- 특정 클래스 입장에서 다른 클래스를 자신의 친구(friend)로 선언하는 것. 대상에게 자신을 public처럼 인식될 수 있게 한다.


클래스 babo는 trash에게 friend를 선언하고 있다.




trash는 friend의 private 멤버인 money에 접근하여 값을 가져가버렸다.


하지만 만약 friend 선언을 안하면 어떻게 될까?



곧장 에러 처리된다. 접근할 권한이 없는 녀석이 접근 했기 때문이다.


위에서도 설명했듯이, babo가 trash를 friend 선언한 상태라고 해도 babo가 trash에 접근할 수는 없다.



2. friend 멤버 함수

- 클래스 전체가 아닌 클래스의 특정 멤버 함수만을 프렌드로 선언.

firend 클래스의 경우, A가 B를 friend 선언시, 난 B의 꺼야! 라고 하는 것으로 B의 모든 멤버 함수가 A에 간섭할 수 있는 반면, friend 멤버 함수 선언시, 난 B의 '멤버 함수' 꺼야! 라고 선언하는 것과 같다. 즉슨 B의 특정 멤버 함수만이 A를 간섭할 수 있고, 그 외의 멤버가 접근하려 들면 단호히 꺼지라고 하는 것.


바보의 하단에 trash의 sendCall 함수를 friend로 선언하고 있는 것을 볼 수 있다.

sendCall 함수를 보다 하단에 정의한 이유는, 그렇게 하지 않으면 컴파일러가 읽어들일 때 babo 객체의 내부구조를 볼 수 없어서 멤버를 건드릴 수 없기 때문이다.


이처럼 접근이 된다.


만약 그 함수가 아닌 짝퉁함수를 선언하여 접근하면 어떻게 될 까?


friend 멤버 함수 선언시 해당 함수가 아니면 접근이 불가능하다는 점을 명심하자.


3. friend 전역 함수

- private, protected 접근 지정자를 무시하고, 클래스 내부의 멤버에 접근할 수 있다.



friend 전역함수는 이와 같이 선언한다.




함수명에 friend 하나 붙였을 뿐인데, privater가 privateFunction을 걷어차버렸다!


이유는 더 이상 멤버가 아니기 때문이다! privateFunction 함수는 더 이상 privater의 소유물이 아닌 것이다.


friend 전역(external) 함수라고 불리우는 이유는 말 그대로 전역함수가 되어버렸기 때문이다. 따라서 아래와 같이 호출한다.



이와 같이 선언해야한다.


그러나 이처럼 선언하면 에러가 뜬다.



왜 일까? 싶지만.. 위에서도 설명했듯, '전역함수'가 되었다.

전역함수에 어떤 클래스인지도 모르는 놈의 멤버를 사용해라! 라고 하면.. 에러부터 내고 보는 것이 인지상정일 것이다. 따라서 아래처럼 수정하면 된다.



해당 class를 인자로 받아 아래와 같이 사용한다.

너무도 자연스럽게 사용해서 이상한 점을 못 느끼겠지만, 이 예제는 지금 private로 선언된 멤버에 외부에서 멋대로 접근하고 있다!


이는 연산자 오버로딩에 무척 중요한 가치를 가진다.


덧붙여 '전역' 함수라고 하였는데, 함수 내부에 선언되었을 뿐 전역적으로 아무에게나 접근이 가능하다. 딱히 대상을 가리지 않는다. 아래의 예제를 보자.




ㄴ 이와 같이 해도 정상적으로 접근된다.


장단점 및 비교 -

장점 :

1. 연산자 오버로딩 등 예외적인 경우 필요하다.

2. 클래스를 사용하는 측면에서 추가적인 함수(접근 함수)의 호출이 필요없으므로 나은 성능을 기대할 수 있다.

단점 :

1. 객체 지향 개념에서는 깽판 그 자체다.

2. 클래스 간의 의존도를 높인다. 유연한 코드가 아니게 된다.


첨부 자료 -

위의 내용들을 작성하면서 작성해보고, 사용한 예제이다. 필요한 사람이 혹여나 있을까 하여 올려둔다. 그게 내가 될 수도 있는 법이고.. 말이다.

friend 테스트.zip



참고한 주소 및 정보 -

http://warmz.tistory.com/890



Posted by GENESIS8

댓글을 달아 주세요

  1. jin 2016.09.30 11:28  댓글주소  수정/삭제  댓글쓰기

    궁금했던 키워드라 찾아봤는데 덕분에 잘 알고 갑니당!

  2. 요원009 2018.04.27 18:19 신고  댓글주소  수정/삭제  댓글쓰기

    훌륭한 예제네요. 감탄하고 갑니다 ㅎ

  3. 두들낙서 2019.12.13 16:27 신고  댓글주소  수정/삭제  댓글쓰기

    재미있고 명쾌한 설명 잘 보고 갑니다~