반응형

 

 

 생각보다 방대한 양과 도대체 무엇부터 봐야 하는지를 몰라서 여기저기 정보들을 찾아 해매다가 정작 Deeplearning을 이해 하는 것보다 링크들 찾아다니면서 용어들을 찾아보는데 시간을 많이 보내게 되는 분들을 위해서.!!!

 

혹시 저와 같이 AI를 공부해보고 싶다고 생각하지만 무엇부터 해야 할지 모르는 막막한 분들이 검색을 하다가, 아주 우연히~~~ 이 링크를 발견하셨다면, 운이 아주 좋은 것 일겁니다.

깊은 내용은 없지만 AI/ Deeplearning 을 이해하기 위해서는 무엇부터 해야 하는지를 아주 간단하게  작성해놓은 스터디 길잡이 .

 

머신러닝을 스터디하기 위한 길잡이

 

머신러닝이라는 단어, AI 라는 단어는 개발자에게 하나의 장벽처럼 느껴집니다.
이유는 C/C++/ JAVA 와 같은 프로그래밍 언어를 익히고 이를 이용하여 프로그래밍 하는 것과는 차원이 다른 무엇인가가 있다는 분위기를 주기 때문이죠.

 

 
그러나 하루를 투자한다면, 머신러닝이 이런거였어?
1주일 정도만 투자해본다면, 머신러닝을 사용할 곳이 없을까? 라는 생각을 하게 됩니다. 
(물론 능숙하게 머신러닝을 자유자제로 적용할 수 있다는 의미는 아닙니다.^^;)

 

 
과연, 그럼, 정말!!! 그럴까요?
 
자 한가지 수학 공식을 써보겠습니다. 엄청 어렵고 복잡한 수학 공식입니다. 정말 아무나 이해할 수 없는 공식이죠.
 
Y: 출력
X: 입력
Y = WX+B
 
( 잉,!!! 뭠미,!!!! 어렵다매...!!!!)
 
바로 이 공식입니다. 
 
이 공식을 저는 정말 쉽게 설명 드리겠습니다.
y는 x에 의해 변하는 w 의 기울기를 가진 직선을 B만큼 이동시킨 것이다.
다시말하면, 기울기가 W이고 X축으로 B만큼 이동하는 직선의 방정식입니다.
 
제가 정말 어려운 공식이라고 예기 해놓고, 직선의 방정식 하나를 왜 적었을까요? 중학교 수학만 배웠어도 알 수 있는 공식인데 말이죠.

 

 
머신러닝이 이런것입니다. 말은 어렵지만 막상 들여다보면 정말 단순한 수학공식 하나가 나옵니다.

 

그러면서 그것을 가지고 머신러닝이 무엇인지를 설명합니다.

 

저는 운이 좋아서 youtube에서 15분에서 20분짜리 동영상 강의 하나를 찾아서 보게 되었는데, 
그 영상을 보고 머신러닝이 뭘의미하는지 이해하게 되었습니다.
 
머신러닝이 뭔가를 설명하기 위해서 대부분 초반에 y=wx+b의 공식을 보여줍니다.
차이점은 x가 주어지고 , y를 찾는 것이 아니라 , x,y가 주어지고 w, b를 찾는 것입니다.

 

정말 단순한 공식이지만, 이를 근간으로 머신러닝의 강의가 시작됩니다 대부분이 말이죠.
 
사실 머신러닝 알고리즘을 모두 구현해서 뭔가를 개발한다는 것은 어쩌면, 어려운 내용일 것입니다.
그렇지만, 우리는 알고리즘 개발이 아니라, 머신러닝을 사용한다는 개념으로 접근해야 합니다. 
(퍼셉트론이 왜 옳은지 증명하고, CNN, RNN등이 정말로 결과값에 수렴하는지, 등을 밝히고 논문을 쓸게 아니라면요. )
 
서론이 너무 길어졌는데요. 머신러닝이 어려운 것이 아니다 라는 예기를 하고 싶었고, 하루만 투자하면, 머신러닝이 뭔지 감을 잡을 수 있다는 예기를 하고 싶었습니다.
 

 

 

1.머신러닝이란 무엇인가? (1일차)

- Linear Regression : 직선을 이용해 예측  (선형 회귀)
- Logistic (regression) classification : 참/거짓, A/B, TRUE/FALSE, ... 분류
- Softmax Regression (Multinomial Logistic Regression) : 여러가지를 분류
- Sigmoid 
- 이외의 관련 주제 : overshooting , Overfitting, learning rate,  gradient descent, data preprocessing ( zero-centered data, normalize )
 

 

 

2. DEEP Learning (3일 분량)

- 개념 : 뉴럴 네트워크이다. 인간의 뉴런을 본떠 만든 구조, 퍼셉트론
- XOR 문제 : 하나의 뉴런으로 해결 불가, 여러개의 뉴런으로 가능
- Backpropagation 
- Vanishing gradient problem 

 

- ReLU
- 초기 값을 잘 줘야 한다.( No All 0's: 초기화시 모든 값은 0이면 안된다.) , Xavier
- Fully connected NN

2. DEEP Learning (3일 분량)

- CNN
- RNN
- 관련 주제 :  Drop out, 앙상블(Ensemble)
 
-------------- 여기까지 하면, 2016년 정도까지의 기술을 확보하신겁니다. -------
 
아래 내용들은 비교적 최신의 기술들과 급격히 발전하는 분야의 기술 들입니다.
 

3. RL( 강화학습 : Reinforcement Learning)

- Q-Network
- DQN
 
이 부분은 더 최신의 기술들입니다.
 

4. GAN( 경쟁학습 : Generative Adversarial Nets)

 
결론.  머신러닝 !!!! 지금 도전해도 늦지 않았습니다.!!!!
 
 
 
위의 주제들 중 가장 기본이 되는 머신러닝, 딥러닝을 아주 체계적으로 쉽게 설명해주는 김성 교수님의 강의가 있습니다. 
아래 링크입니다. 
https://www.youtube.com/watch?v=BS6O0zOGX4E&list=PLlMkM4tgfjnLSOjrEJN31gZATbcj_MpUm
 
이 강의를 통해서 쉽게 머신러닝에 입문(?) 할 수 있을거라 생각합니다.
 

인공지능 블로그 사이트 조사

 

AI Dev site : 

다양한 주제들에 대해서 다루고 실천하고 있는 사이트입니다.

여러가지 뉴스들이나 주제들을 살펴볼수 있어요.

http://aidev.co.kr/

 

 

 

인공지능 블로그- 조대협

다양한 분야에 대해서 다루고 계시는 조대협 님이신데요.

역시나 머신러닝에 대해서도 다루고 계십니다.

http://bcho.tistory.com/m/1208

 

 

머신러닝 스터디

제가 머신러닝을 쉽게 이해하고 접근 할 수 있었던 계기는 바로 아래 링크의 강의 내용 때문이었습니다.

https://www.youtube.com/watch?v=BS6O0zOGX4E&list=PLlMkM4tgfjnLSOjrEJN31gZATbcj_MpUm

 

https://hunkim.github.io/ml/

 

 

IMROOT 의 AI 스터디

http://www.iamroot.org/xe/index.php?mid=AI&page=2

 

인공지능 개론

AI 사용 분야에 대해서 살펴 볼 수 있는 주제의 슬라이드입니다.

사실 딥러닝을 어느정도 이해하고 나면 이걸 어디다 사용하지? 라는 질문을 스스로에게 하게 됩니다.

정말 많은 분야에서 사용할 될 수 있지만, 막상 주위에서 찾아보려면 쉽지 않습니다.

어떤 분야에서 사용되고 있는지 살펴볼 수 있는 자료입니다. 

https://www.slideshare.net/medit74/ss-74123546

 

 

 

Creating AI chat bot with Python 3 and Tensorflow

대화형 챗봇을 만들는 과정에서 뇌의 활동과 흡사하게 디자인 한 내용입니다.
뇌와 AI를 동시에 리뷰하여 디자인.
 

https://www.youtube.com/watch?v=q44fefORi1k

 

 

 

텐서플로우에서 제공하는 한국어 가이드 북입니다.

https://tensorflowkorea.gitbooks.io/tensorflow-kr/

https://tensorflowkorea.gitbooks.io/tensorflow-kr/content/g3doc/tutorials/mnist/beginners/

 

 

C++ 로 Deeplearning 스터디하기

https://blog.naver.com/atelierjpro/220697890605

 

키워드

Tensorflow, Caffe, Keras

pytorch

Linear Regression

Perceptron

Merchin Learning

Deep learing

Neural Network

ANN ( Artificial Neural Network)

CNN

RNN

LSTM

Big Data

Robotics

지도 학습 ( Supervised Learning)

비지도 학습(Unsupervised Learning)

인지 컴퓨팅

강화 학습(Reinforcement Learning)

KNN

SVM

Decision Tree

Logistic Regression

K-Means Clustering

DBSCAN Clustering

Hierarchical Clustering

MDP: Markov Decision Process

회귀(Regression) 와  분류(  Classification)

Over fitting

Under fitting

Normal Fitting

 

경쟁학습 GAN

 

LLM : Large Language Model

openai

chat GPT

Dall-E

stable diffusion

 

반응형




http://www.ogre3d.org/docs/api/2.0/





3D graphics 와 관련된 다양한 수학, 기하학, 수식들의 구현을 확인해 볼 수 있습니다.



http://www.ogre3d.org/docs/api/2.0/_ogre_matrix4_8h_source.html

예로 위 link는 matrix4 에 대한 link입니다.


반응형

Github를 사용하다보면 콘솔에서 git을 사용해야 하는 경우들이 있습니다.

간단하지만 유용한 팁입니다.

 

 

git commit 

 

 

github 를 사용하는 경우 patch set 을 추가하는 방법은 아래와 같습니다.

 

이미 commit을 하나 올렸는데 해당 commit에 수정사항을 추가하고 싶은 경우 아래와 같이 사용하면 됩니다.

 

git add "추가 수정한 파일들"

 

git commit --amend   --> 이전 commit 에 추가

 

git push origin +branch 명

 

"+" 를 이용하여 해당 branch에 push를 하면, 이전 commit에 append됩니다.

 

 

 

 

git log 

git log 를 통해서 어떤 commit 들이 추가되었는지 히스토리를 파악할 수 있습니다.

그런데 가끔은 로그를  메일등에 commit들을 첨부해서 보내야 하는 경우나 한눈에 짧게 보고 싶은 경우들이 발생하죠.

 

이럴때 쓸 수 있는 간단한 팁입니다.

 

git log --oneline : 이렇게 하면 1줄 단위로 listup 되어 보입니다.

 

 

음 그런데 막상 이렇게 해서 보니까. 줄도 안맞고 hash키도 잘 안보이고 합니다.

포멧을 내가 정하면 좋겠다.. 는 생각이 막 들죠???

 

이럴때 --format을 사용합니다.

 

git log -5 --date=short --format="%H %ad %<(20)%an %<(80,trunc)%s"

 

git log --help 를 보시면,

%H  : hash key입니다.'

%ad : 작성 날짜   : --date 로 설정한 값으로 표시 됩니다.

%an : 작성자 이름

%s : commint message 입니다.

 

여기에 format을 맞추기 위해서  %<(20) 은 뒤에 %an 공간을 20자 버퍼를 두겠다는 의미입니다. (줄맞춤 용도이죠)

%<(80,trunc) 은 %s 의 공간은 80자 공간이고, 넘으면 글자를 자르겠다는 의미입니다.

 

 

이외에도 다양한 방식으로 출력 형태를 사용할 수 있겠죠.?

 

 

 

git log -5 --format="%H %ad %an %s"

 

 

git log --format="<tr>\

<th>%H</th>\

<th>%ad</th>\

<th>%an</th>\

<th>%s %>|(30)</th>\

</tr>"

 

 

 

반응형

REST (Representaional Safe Transfer , Representaional State Transfer)

웹 창시자 중의 한사람인 로이 필딩(Roy Fielding)이 2000년에 발표한 논문에 의해서 소개되었습니다. 현재의 아키텍처가 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다고 판단했기 때문에 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍처를 소개했는데, 이것이 바로 REST입니다.


REST는 근래에 들어 HTTP와 JSON을 함께 사용하여 OPEN API를 구현하는 방법으로 주류를 이루고 있으며, 대부분의 OPEN API는 이 REST 아키텍처를 기반으로 설계 및 구현되고 있습니다.



REST는 크게 리소스, 메서드 , 메세지 3가지 요소로 구성됩니다.

예를 들어서 "이름이 Terry 인 사용자를 생성한다" 라는 호출이 있을때 '사용자'는 생성되는 리소스, '생성한다'라는 행위는 메소드, 그리고 '이름이 Terry인 사용자'는 메세지가 됩니다.

이를  REST 형태로 표현해보면 ,

'생성하다' 메소드 - HTTP POST 메서드

'사용자' 리소스 - http://myweb/users 라는 형태의 uri 

'생성하고자 하는 사용자 Terry' - JSON 문서로 표기

HTTP POST , http://myweb/users/

{

    "users":{

           "name":"terry"

    }

}


REST에서는 앞에서 잠깐 언급한 바와 같이 행위에 대한 메서드를 HTTP 메서드를 그대로 사용합니다.

HTTP에는 여러가지 메서드가 있지만, REST에서는 CRUD(Create Read Update Delete) 에 해당하는 4가지의 메소드만 사용합니다.

POST - Create

GET - Select (의미상 Read)

PUT - Update

DELETE - Delete

이와 같이 4개의 method가 CRUD에 대응됩니다.


Idempotent (멱등성) - 몇번을 수행해도 같은 결과가 나오는 것을 의미합니다.

예를 들면, a++ 은 항상 결과가 1이 증가되기 때문에 "Idempotent 하지 않다"고 하고, a=4 는 항상 4가 a에 대입되기 때문에 "Idempotent 하다"고 합니다.

POST 연산은 리소스를 추가하는 연산이기 때문에 Idemopont 하지 않습니다.

GET,PUT,DELETE는 반복 수행해도 Idempotent 합니다.

이 Idempotent의 의미가 중요한 이유는 , REST 는 개별 API를 상태 없이 수행하게 됩니다. 그래서 해당 REST API를 다른 API와 함께 호출하다가 실패하였을 경우에, 트랜젝션 복구를 위해 다시 실행해야 하는 경우가 있는데, Idempotent하지 않은 메소드의 경우에는 기존 상태를 저장했다가 다시 원상복구 해줘야 하지만, Idempotent한 메소드의 경우에는 반복적으로 다시 메소드를 수행해주면 됩니다.

개시물 조회 API를 만들었는데, 개시물을 조회할때마다 조회수를 +1 자동으로 하도록 되어있다면, 조회 실패시에는 -1을 다시 해줘야 합니다.


REST 리소스

REST는 리소스 지향 아키텍처 스타일이라는 정의 답게 모든 것을 리소스, 즉 명사로 표현하며, 각 세부 리소스에는 ID를 붙입니다. 즉, 사용자라는 리소스 타입을 http://myweb/users라고 정의 했다면, terry라는 id를 갖는 리소스는 http://myweb/users 라는 형태로 정의합니다.


REST 의 리소스가 명사의 형태를 띄우다 보니 명령(opertation) 성격의 API를 정의하는 것에서 혼동이 올수 있습니다. 예를 들면 "푸시 메시지를 보낸다"라는 보통 기존의 RPC(Remote Procedure Call)나 함수성 접근에서는 /myweb/sendpush 형태로 정의될 수도 있습니다.

동사를 명사형으로 변경하여 "푸시 메시지 요청을 생성한다" 라는 형태로 정의를 변경하면 POST/myweb/push 형태와 같이 명사형으로 정의 할 수 있습니다.

모든 형태의 명령을 이런 형태로 정의가 가능한 것은 아니지만, 될수 있으면 리소스 기반의 명사 형태로 정의하는 게 REST 형태의 디자인이 됩니다.


예)


생성

HTTP Post, http://myweb/users/

{

   "name":"terry",

   "address":"seoul"

}


조회

HTTP Get , http://myweb/users/terry


업데이트


HTTP PUT, http://myweb/users/terry

{

  "name":"terry",

  "address":"suwon"

}


삭제

HTTP DELETE, http://myweb/users/terry



[참고 : 조대협의 서버사이드 대용량 아키텍처와 성능 튜닝 - 조대협]


'Node.js , React, Docker' 카테고리의 다른 글

[React] Components  (0) 2024.09.07
[AWS] 여러가지 알아야 할것들  (3) 2024.07.12
Docker 간단히 이해하기  (0) 2024.07.11
[Docker] proxy 문제 해결  (0) 2021.11.11
react 시작하기!!  (0) 2016.12.29
반응형

Text를 표시 할때 생각보다 고려해야 할 사항들이 많습니다.



[Android]

안드로이드 쪽은 이와 관련해서 살펴보려면, TextView와 TextAttribute 를 살펴보는 것이 좋습니다.

https://developer.android.com/reference/android/widget/TextView.html

https://developer.android.com/reference/android/text/FontConfig.html

https://developer.android.com/reference/java/awt/font/TextAttribute.html





[Tizen]


https://developer.tizen.org/development/guides/native-application/user-interface/efl/fonts


EFL 의 textblock에 style 지정하는 방식이 정리된 link입니다.

description
{
   text
   {
      font: "Tizen:style=Regular";
      font_size: 36;
      text_class: "label";
   }
}
description
{
   text
   {
      font: "Tizen:style=Regular";
      font_size: 36;
      text_class: "tizen";
   }
}



Table: Supported font styles

Font featureStyle attribute
font_stylenormal
oblique
italic
font_widthnormal
ultracondensed
extracondensed
condensed
semicondensed
semiexpanded
expanded
extraexpanded
ultraexpanded
font_weightnormal
thin
ultralight
light
book
medium
semibold
bold
ultrabold
black
extrablack




반응형

오른쪽 참조, R-Value Reference 란?

 

 

시기는 잘기억이 안나는데 어느시점에서 부턴가 C++ 쪽에서 rvalue , move sementic 이런 용어들이 자주 거론 되기 시작한 시기가 있었습니다.

꽤 많은 사람들이 여기에 대해서 유익한 개념이라고 언급했던 기억이 나네요.

 

블로그로 정리하기에는 좀 오래된 내용이지만, 한번 머리속을 정리해볼겸해서 작성하게 되었습니다.

 

 

C++11 에서 도입된 새로운 특성중 의미이동(move semantic) 과 오른쪽 참조가 있습니다.

이것은 불필요한 복사를 줄이는 것을 목적으로 합니다.

 

여기에 대해서 알아보기 전에 이미 C++의 특성에 대해서 많이 알고 계신 분도 있겠지만, 그렇지 못한 분들도 있을것이라서 ,

기본이 되는 내용이지만 생성자, 복사 생성자 등에 대해서 언급을 하고 넘어가겠습니다. 

 

 

객체 복사와 복사 생성자

 

객체 복사와 복사 생성자를 설명하기 위해 간단한 예제를 준비 했습니다.

getMyObj()는 MyObj의 지역(local) 객체를 반환합니다.

MyObj getMyObj()
{
  MyObj temp;
  temp.set(10);
  return temp; // temp 라는 지역 객체(local object)를 리턴합니다.
}

//지역(local) 객체는 의 life cycle 스코프(scope)을 벗어나면 삭제됩니다. 따라서 위의 함수에서 return한 temp 의 삭제 시점이 매우 중요합니다.
//아래 main 함수에서는 a라는 객체를 선언하면서 getMyObj(); 를 호출 했습니다.

int main(void)
{
  MyObj a = getMyObj();  //(1) 임시 객체 temp 가 a로 복사되고, temp는 사라짐

  MyObj b = a;     //(2) a를 b에 복사함.
  b.printData();
}

 

MyObj 라는 클래스(class) 형태가 어떤 모양일지는 모르겠지만,

main 함수의 문맥상으로는 크게 문제될 것이 없어보입니다.

getMyObj() 가 로컬 객체를 넘겼다 하더라도, a 로 복사(copy)가 발생 할 것이고 , a는 다시 b로 복사(copy) 될 것으로 보이기 때문입니다.

그렇지만 MyObj가 아래와 같은 class라고 한다면, 기능상 심각한 오류가 발생할 가능성이 있습니다.
class MyObj
{
  int* __data = nullptr;

  public:
    MyObj()    // 일반 생성자
    {
       	__data= new int[3000];
		for (int i = 0 ; i < 3000 ; i++)
	 		__data[i] = 0; 
    }

    virutal ~MyObj()
    {
		delete __data;
    }    

    void set(int val)
    {
		for (int i = 0; i < 3000;i++)
			__data[i] = val ;
    }
    
    void printData(){
        for ( int i =0; i<3000;i++)
               printf("data[%d] = %d", i, __data[i]);
    }

};
 
위의 main 함수에서 getMyObj()를 호출하여 temp 가 삭제 되는 부분을 다시 살펴봅시다.
   MyObj a = getMyObj();  //(1) 임시 객체 temp 가 a로 복사되고, temp는 사라짐

이 과정을 좀 풀어서 얘기하면 다음과 같습니다.

1) getMyObj() 함수는 temp를 return합니다.

2) temp는 a에 복사가 됩니다.

3) temp는 삭제가 되면서 __data 를 삭제(delete)합니다.

4) 여기까지 진행되면, a.__data는 삭제된 메모리 주소를 가리키게 됩니다.(dangling pointer)

이 내용을 좀더 자세히 확인하기 위해서는 복사 생성자를 알아봐야 합니다.
 

복사 생성자 (copy constructor)

 

사용자가 작성한 복사 생성자가 아닌, 컴파일러(compiler) 가 제공하는 기본 복사 생성자는 다음과 같이 동작 하게 됩니다.

 

MyObj( const MyObj& obj)

{

   __data = obj.__data;  //a.__data 는 address를 담고 있는 값이라서, __data에 해당 주소값(address) 만 복사가 됩니다.

  // 복사 생성자가 없는 경우 default 복사는 이것과 동일한 결과를 만듭니다.

}

 

__data라는 포인터(pointer,주소를 담을 수 있는 변수) 값을 복사하게 됩니다.

 

MyObj b=a; 라는 코드를 보면, 

a.__data는 메모리 주소값을 담을 수 있는 변수이기에, a._data 값을 b.__data 로 주소만  복사하지,  __data가 가리키는 곳의 실제 데이타를 복사 하지 않습니다.

결과적으로  a와 b가 모두 같은 주소를 바라보는 __data를 갖게 됩니다.

이 경우  a가 삭제된다면,  b.__data가 가리키고 있는 곳의 data를 메모리가 해제 되었기 때문에, b.__data 는 dangling 된 pointer가 됩니다.

 

때문에 MyObj b=a; 에서는 반드시 복사가 이뤄져야 합니다.

 

이 때문에 복사 생성자는 다음과 같이 작성되어야 합니다.

 

MyObj(const MyObj& obj)  // 복사 생성자

{

__data= new int[3000];

for (int i = 0; i < 3000;i++)

__data[i] = obj.__data[i] ;

}

 

반면에,

MyObj a = getMyObj();
 
에서 data를 모두 copy하는 과정은 temp 객체는 더이상 사용할 일이 없기 때문에 불필요한 작업입니다.
그런데 class MyObj가 들고 있는 data의 내용이 크고 복잡하다고 한다면,  상당히 많은 시간을 소모하게 됩니다.
 

A의 data가 커지면 커질수록, 복잡해지면 복잡해질 수록 복사 비용은 커지게 됩니다.

 

맨 처음 코드의 main() 함수에서 보면, (1)(2)가 미묘하게 다릅니다.

 

(1)은 임시 객체를 a에 복사하는 것이고,  (정확하게는 미묘한 어떤 것이 더 있긴 하지만 설명의 편의를 위해 여기까지만)

(2)는 b에 임시 객체가 아닌 a를 넘기는 것입니다.

 

C++ 개발자들(C++언어를 개선하고자 하는 사람들)은 여기에 착안을 해서 복사와 이동을 분리해서 생각하게 되었습니다.

다시 생각해보자면,

(1) 은 데이타를 넘겨주고 임시 객체는 사라지기 때문에 사실상 이동과 동일합니다..

(복사를 하고 삭제한다.!)

(2) 는 데이타를 넘겨주고 객체가 2개 다 유지가 되기 때문에 복사에 해당합니다.

 

(1)과 같이 이동을 원하는 경우에는 복사 생성자를 통한 처리가 아니라 다른 함수를 제공하게 되면 훨씬 성능에 이득을 취할수 있게 되죠.

 

void MoveFrom(MyObject& from)

{

   __data = from.__data; // data를 copy 하는 것이 아니라 주소만 복사함.

   from.__data = nullptr; // 원본의 data는 nullptr로 만듬. 삭제가 안되도록.

}

 

 

 

a.MoveFrom(getMyObj());  

 

이렇게 사용하면 됩니다.

 

 

이것의 단점은 ,

1. 객체를 생성하는 시점에 처리 할 수 없습니다.

 

2. 넘겨주는 객체가 더이상 사용안되는지 사용되는지 판단을 개발자가 해야 하여 실수의 여지가 있고,

   코드가 변경될때 마다 항상 다시 확인을 해야 합니다.

 

3. 함수 형태로 클래서 설계자가 작성을 해야 하기 때문에, 이름과 사용처라 모두달라 유지 보수가 힘듭니다.

 

 

 

이런 이동에 대한 고민과 경험들은 C++언어의 개선에 도움 되었고, 의미 이동이라는 개념과 R-Value Reference 라는 것이 

C++11에 추가가 되었습니다.

 

 

C++ 개발자들은 이 move semantic 과 R-value reference 에 대해서 사람들은 드디어 획기적인 성능 개선이 이뤄질 수 있겠다는 기대들을 하게 됩니다.

 

실제로 STL 전반에 걸쳐서 의미 이동이 추가되어 상당한 성능 개선이 이루어졌습니다.

 

 

 

자 이제 R-Value Reference 라는 것이 무엇인지, 이것에 의해서 무엇이 달라지는지 보도록 합시다.!!

 

 

오른쪽 참조, R-Value Reference 란?

 

 

오른쪽 참조는 임시 객체와 매우 밀접합니다.

 

다음 식으로 L value 와 R value를 간단히 설명드리겠습니다.

 

A = B  라는 식이 있다고 한다면,

 

A는 L-Value 이고 B는 R-Value 입니다. 즉 왼쪽에 있는 값은 L value, 오른쪽에 있는 값은 R value로 보면 됩니다.

왼쪽 편에 있는 값들은 뭔가 저장할 수 있는 것이어야 합니다.

12 =B  이런식으로 12라는 상수값은 사용될 수 없습니다.

 

오른쪽 값 형식은 상수나 변수 모두 올 수 있습니다.

A = 12

A = B+4

A = 4-3

A = B   // 실질적으로 L-value = L-value 라서 복사 생성자가 실행됨.

 

R-Value를 좀 다르게 표현하면, L value에 assign하기 위한 임시적인 값 이라고 표현하는게 더 올바른 것 같습니다.

 

편의상 임시 객체라고 표현 하겠습니다.

 

정수에 대한 처리를 위한 Integer라는 class가 있다고 합시다.

 

Integer a;   // a는 일반 객체

 

Integer b = a;  // b는 일반 객체,  a는 일반 객체

 

Integer c = 10; // c는 일반 객체, '10'을 담는 임시 객체 생성

 

Integer d = b+c;  d,b,c는 일반객체,  (b+c)는 b와 c를 더한 결과를 담는 임시 객체 생성

 

 

우리가 연산자등을 이용할때 임시 객체들이 의도치 않게 생성되는 경우들을 흔히 볼수 있습니다.

고수 개발자 분들은 코드를 볼때 그런 부분들 까지 염두해 두고 살펴보죠.

 

이때 이런 임시 객체들은 한번 생성되고 바로 버려지는데, 이를 복사하기 위해서 소비되는 비용( 리소스, CPU) 가 너무 아까운 것이죠.

이런 부분들은 바로 성능에 영향을 미치게 되고 말이죠.

 

그리고 이런 부분들을 개발자들에게 맡기기에는 너무나 불안한 요소들이 너무 많아서, 임시 객체를 처리하기 위한 특별한 문법이 추가되었습니다. 

 

R-Value Reference 라고 합니다.  형식은 "&&"  입니다.

&&??? 이게 뭐냐구요?

 

타입명&& 변수 이렇게 사용을 하게 되면, 임시 객체를 가리키는 레퍼런스가 만들어지게 됩니다.

 

void Integer::Get(Integer&& value)  이런 형식이죠.

 

만약  아래와 같이 2개의 함수가 만들어진다고 하면,

void Integer::Get(Integer&& value)   --> 임시 객체가 인자로 들어올때 처리되는 함수

void Integer::Get(const Integer& value)  --> 일반 객체가 인자로 들어올때 처리되는 함수

가 됩니다.

void Integer::Get(Integer&& value) 이 함수가 없다면, 모든 객체에 대해서 void Integer::Get(const Integer& value) 가 동작하게 됩니다.

 

 

 

그럼 처음에 만들었던 MyObj class에 이동 생성자를 추가해봅시다.

 

이동 생성자는 인자로 받는 객체가 임시 객체이기 때문에 더이상 사용 안되고,사라질 것을 전제로 작성되어야 합니다.

 

MyObj(MyObj&& obj)  // 이동 생성자

{

__data = obj.__data; // 주소 복사

obj.__data = nullptr; // 이전 객체에서 pointer는 삭제,

//이동 완료.

}

 

 

입력으로 받은 obj는 바로 사라질 것이기 때문에,  obj의 data를 nullptr로 변환 하는 것은 꼭 필요합니다.

그렇지 않으면,  임시 객체인 obj의  destructor에서 __data를 delete 하여,  현재 객체의 __data는 dangling pointer가 되어버립니다.

 

 

 

class MyObj

{

  int* __data= nullptr;

 

  public:

    MyObj()    // 일반 생성자

    {

       __data= new int[3000];

for (int i = 0 ; i < 3000 ; i++)

__data[i] = 0; 

    }

 

   MyObj(const MyObj& obj)// 복사 생성자

    {

__data= new int[3000];

for (int i = 0; i < 3000;i++)

 __data[i] = obj.__data[i] ;

    }

 

   MyObj(MyObj&& obj)  // 이동 생성자

    {

__data = obj.__data; // 주소 복사

  obj.__data = nullptr; // 이전 객체에서 pointer는 삭제,

  이동 완료.

}

    virutal ~MyObj()

    {

delete __data;

    }    

 

    void set(int val)

    {

for (int i = 0; i < 3000;i++)

 __data[i] = val ;

    }

};

 

MyObj getMyObj()

{

  MyObj temp;

  temp.set(10);

  return std::move(temp);

}

 

int main(void)

{

  MyObj a = getMyObj();  //(1) MyObj(const MyObj&& obj) 이동 생성자가 호출됨

  MyObj b = a;     //(2) MyObj(const MyObj& obj) 복사 생성자가 호출됨.

}

 

 
이렇게 이동 생성자와 복사 생성자를 모두 구현해 놓으면,
프로그램 코드에 따라 경우에 따라서 복사가 되고나, 이동이 됩니다.
 
 
 
 
std::move()
 
std::move()는 의미 이동을 위한 도구중 하나입니다.
 
MyObj b = a; 는 복사 생성을 하게 됩니다.
MyObj b = std::move(a); 라고 하게 되면, b는 이동 생성을 하게 됩니다.
 
이런 식으로 경우에 따라서 복사를 이동으로 변환하여 처리 할 수도 있습니다.
이런 강제 이동의 이면에는 이에 따른 불안 요소를 남기게 됩니다.
즉, b로 강제 이동을 했지만, a는 현재 살아있는 상태(변수이기 때문에)이기 때문에 만약 a를 사용하려 한다면, a.__data 는 nullptr 상태이기 때문에 문제가 생깁니다.
 
즉, std::move() 를 사용할 수 있는 경우는 a를 더이상 사용 안해야 합니다.
 
 
 
 
 
 
 

생각해볼 만한것.!

 

컴파일러나 언어 차원에서 성능 개선을 위해 최적화를 해주는 부분들이 존재 합니다.

그런것에 대해서 적어봤습니다.

 

B = 5

A = 10

A = B

 

A = B 에서 A는 복사가 됩니다.

 

그러나 원리를 따지자면,

원래는 B쪽은 r value가 되어야 합니다. 따라서, 다음과 같은 과정이 되어야 합니다.

1. 임시 객체를 만들고 거기에 B가 copy 된다.   

  temp의 복사 생성자를 통해 B가 temp 로 복사가 된다.

   temp(B)  // temp 는 임시 객체 , B는 인자.

 

2. A에게 임시 객체를 넘긴다.  

    A의 이동 연산자를 통해 temp가 A로 이동한다.

    A = temp(B) 

 

그러나 실제로는 이런 불합리한 점을 제거하기 위해서 예외적으로 A의 copy construct 로 처리 됩니다.

 

L value = L value 의 경우에는 copy라고 보시면 됩니다.

 

 

 

Integer getInt()

{

  return Integer(10);

}

 

Integer B = getInt();

 

이런 코드의 경우에는 B의 이동 생성자가 불려서 임시 객체가 copy 되어야 합니다.

그러나 컴파일러가 이런경우는 이동 생성 없이 B 가 곧 임시 객체가 되도록 만들어 줍니다.

마치,

Integer&& B = Integer(10); 

이런 것 처럼 만들어줍니다.

 

이 경우 만약 아래와 같이 복사보다는 move가 낳지 라고 생각해서 아래와 같이 move를 명시화 시킨다면,

Integer B =  std::move(getInt());

 

B의 move 연산자가 동작하여 오히려 성능에 안좋은 영향을 주게 됩니다.

 

반응형

undefined symbol error는 흔히 어떤 함수를 사용하려고 하는데, 

실제 함수의 구현체가 없는 경우에 linking 하는 과정에서 발생하는 에러입니다.


개발자가 보기에는 에러가 발생안해야 하는데, 이상하게 발생한다고 느껴지는 경우들이 종종 있습니다.


몇가지 경우를 살펴봅시다.



1) header file에만 해당 함수가 정의되어있고 구현부가 없는 경우,

만약 바이너리(binary)로 되어있는 lib과 h 파일을 사용하는 경우, lib안에 해당 함수가 구현이 안되어있을 것입니다.


2) binary에도 구현이 되어있는데, 안되는 경우,

binary 가 so또는 dll 과 같이 shared lib으로 만들어졌을때에, 해당 함수가 export안되어 있어서, 외부에서는 사용할 수 없는 경우입니다.


3) 구현도 되어있고 export 되어있는 경우,

c 로 작성된 함수여서 cpp 파일에서 사용하려고 할때 naming 이 mangling 되어 문제가 발생할 수 있습니다.

ex) void abcd(int a) 라는 함수가 c로 작성된 API명은  _abcd 라는 symbol을 제공하는데,

cpp에서 include 해서 사용하려다 보니 _abcdi 와 같은 전혀 다른 이름으로 호출이 되어 발생할 수 있습니다.

extern "C" 로 해결이 가능한 부분입니다.


원인은 대부분 이 3가지 경우들에 포함될것 입니다.


이 와 관련 내용으로 아래 링크에 따로 정리되어 있습니다.


C++ 상에서 발생하는 name mangling 에 관한 내용


 

<참고>

undefined symbol error와 관련해서 색다른 사용법과 회피 방법이 있습니다.


프로젝트를 진행하다보면,

build 환경에는 symbol이 없고, 실행 환경에만 library가 있다거나 symbol이 있다거나 하는 경우들이 발생합니다.

이럴 경우, build 시점에 undefined symbol error들이 발생하는데,

이를 회피 하고자 할때 사용하는 방법이

link option에서 undefined symbol을 무시하는 방법이 있습니다.

 

linux 의 ld 옵션  https://linux.die.net/man/1/ld

 

ld 옵션 중에  --allow-shlib-undefined 가 있습니다.

 


link option에  --allow-shlib-undefined 를 주게 되면,  undefined symbol이 발생하더라도,  build error 를 발생시키지 않고 

바이너리를 만들어내게 됩니다.



부득이한 경우에 회피할 수 있는 방법이긴 하나, 전체적으로 보면 이는 좋은 방법은 아닙니다.


이 옵션이 켜진 상태로 프로젝트를 진행하다보면, 실제로 함수구현이 빠진 부분을 발견하지 못하고 넘어갈 수도 있습니다.


그렇게 되면 원인을 찾는데 매우 큰 시간이 들게 됩니다.



'Linux' 카테고리의 다른 글

relro,Stack Canary 방어  (0) 2018.06.05
tput: no value for $term 에러 발생  (0) 2017.11.21
open 되어있는 fd 확인하기.  (0) 2017.03.03
프로세스의 메모리 사용량  (0) 2017.01.11
rpm 사용법  (0) 2014.02.13
반응형

코딩이나, 디버깅을 하다보면,


open되어있는 fd들을 확인해보고 싶을 때가 있습니다.


어떤 socket이 열려 있는지,  어떠 파일을 지금 사용하고 있는지 등등 말이죠.



리눅스에서는 process 별로 확인할 수 있는 방법이 있습니다.


/proc/ "pid"/ fd


여기에 들어가서 ls를 해보면, 사용중인  fd들을 확인할 수 있습니다.





 

'Linux' 카테고리의 다른 글

tput: no value for $term 에러 발생  (0) 2017.11.21
link error, undefined symbol  (0) 2017.03.28
프로세스의 메모리 사용량  (0) 2017.01.11
rpm 사용법  (0) 2014.02.13
Linux 커널 드라이버 모형: 협업의 장점 - in Beautiful code  (0) 2010.10.22

+ Recent posts