[컴][디버그] Immunity Debugger 이뮤니티 디버거 사용법 - 목차


[컴][c/c++] rvalue reference 와 move semantics

rvalue 와 move / c++11 에서 rvalue 와 move

 

rvalue

rvalue 는 assignment 의 right 을 뜻한다.

int a  = b;

라는 code 가 있다면, b 가 rvalue 를 이야기 하는 것이다. 참고로, 여기서 rvalue 와 상대적인 의미로 a 를 lvalue 라고 한다. 물론 이렇게 이름이 붙은 이유는 정말 단순하게 assignment(=) 의 오른쪽에 있는 녀석들이 그런 특징을 가지고 있기 때문이다. 하지만 단순히 "= 기호 오른쪽에 있는 녀석을 뜻한다." 라는 것만으로는 rvalue 가 구체적으로 무엇을 이야기 하는지 알기 어렵다.

그런데 ref. 1 에서 rvalue 와 lvalue 를 구분 짓는 좋은 방법을 이야기 해 준다. &(address)를 사용할 수 있는지 여부로 판단하라고 한다.

int a = b;

위의 식에서 &b(b의 address) 는 의미가 있나? "있다." 그렇다면 b 는 lvalue 이다.

assignment 의 right 이 rvalue 라고 했는데 아닌가? 좀 헷갈린다. 일단 아래 식을 보자.

int a = b+c;

이 경우 &(b+c) 는 어떤 의미인가? 이 경우는 compile error 가 난다. 즉 의미가 없다. b+c 는 temporary value 이기 때문에 b+c 의 address 를 구할 수 없는 것이다. 그러므로 (b+c) 를 rvalue 라고 할 수 있다.

rvalue 는 그래서 temporary 의 뜻을 내포한다고 볼 수 있다. 우리가 =(assign) 을 사용할 때 오른쪽에 놓는 값을 생각해 보자. 오른쪽에 있는 값을 왼쪽에 넣는 것이기 때문에, 결과적으로 우리는 왼쪽(lvalue) 만 가지고 있으면 되는 것이다. 오른쪽(rvalue) 의 값을 왼쪽(lvalue) 가 가지고 있기 때문에 오른쪽을 굳이 가지고 있을 필요가 없다.

 

 

move semantics

그럼 이 rvalue 라는 개념을 이용해서 무엇을 하려고 하는 것일까? c/c++ 에서 move semantics 라는 말을 사용한다. 굳이 해석을 하자면 "move 의 개념" 정도로 해석하면 될 듯 하다. 이 move semantics 를 구현해 주기 위한 도구로 rvalue 를 만들어 낸 듯 하다. 적어도 rvalue 를 통해 move semantics 를 구현하는 것은 맞다.[ref. 2]

그럼 이 move semantics 가 무엇을 이야기 하는 것일까. 흔히 사용하는 windows explorer 에서 파일의 "복사" 와 "이동" 의 개념을 알고 있다면 move semantics 도 이해할 수 있다. move 는 말 그대로 "이동"을 하는 것이다. 이것은 std::vector 의 method 를 보면서 이해를 해 보자.

std::vector<int> v;
int a = 10;
int b = 20;

v.push_back(a); // copy
v.push_back(std::move(b)); // move

위의 코드에서

v.push_back(a)

같은 경우는 "복사"(copy) 이다. 그래서 a 도 남아있으면서, 동시에 v 에 '10' 이 생겼다. 아래처럼 2개의 '10' 이 존재하는 것이다.

 a                  v
+---------+ +--------+
| | | |
| | | |
| 10 | | 10 |
| | | |
| | | |
+---------+ +--------+

하지만,



v.push_back(std::move(b)); // move


을 보자. 이 경우 push_back() 은 move 를 구현했다. 그래서 b 의 값이 v 로 옮겨간다. 실제로 구현은 어떻게 되어 있는지 모르지만, 이것은 c/c++ 에서 shallow copy 같은 느낌이다. 다시 이야기 하면, pointer 로 address 만 바꾸는 식의 느낌이다. (물론 느낌만 그렇단 이야기이다.)


 b                  v
+---------+ +--------+
| | | |
| | | |
| XX | | 20 |
| | | |
| | | |
+---------+ +--------+

이것이 move semantics 이다.


 


 


rvalue 와  move


그렇다면 이것을 어떻게 rvalue 가 어떻게 이것을 구현하는 데 도움을 주는 지 보자.


위와 같은 code 에서 v.push_back(a) 는 기존의 우리가 사용해 오던 함수(method)이다. 그래서 그냥 a 값을 vector 안에 복사해서 넣게 된다. 이 때 호출되는 vector.push_back 는 아마도 아래처럼 lvalue reference 를 argument 로 사용할 것이다.(return type 이나 template 같은 keyword 는 잊어버리자. 이해를 위해 단순하게 설명한다.)



push_back(int& a){}


하지만 v.push_back(std::move(b)) 는 조금 다르다. move(b) 는 b 를 rvalue 로 cast 하게 된다. 즉, argument b 를 rvalue 라고 얘기해 준다. 그래서 vector 의 push_back() 함수 중 argument 가 rvalue 와 관련된 녀석을 호출되게 해 준다.



push_back(int&& b){}


위처럼 rvalue reference 를 argument 로 사용하는 함수를 호출하게 될 것이다.


이렇게 argument 의 type 을 통해서 함수가 move 가 될지 copy 가 될 지 정하게 된다. 그냥 push_back_by_copy(), push_back_by_move() 같이 함수를 따로 두는 것보다는 확실히 코드가 예쁘다. ^^;;;


이런 식으로 STL 에서는 std::move() 를 통한 move semantics 를 구현해 놓았다. 그래서 이제 c++에서 좀 더 효율적인 코드를 짜는 데 도움을 줄 것이다.[ref. 2]


 


 


설명이 많이 부족하다. 좀 더 자세한 이해를 위해서는 refereces 나 다른 자료들을 좀 더 찾아보기 바란다.


ref. 1 에서 rvalue 에 대한 개략적인 이해를 할 수 있으며, 실제 사용과 관련해서는 ref. 2 의 글을 읽는 것이 도움이 될 듯 하다.


 


 


References



  1. STL Introduction lecture links Part 9 (rvalue references), channel 9, MS, 2010년 11월 29일
  2. Move semantics and rvalue references in C++11, cprogramming.com

[컴][GAE] urlfetch, how to get the UTF-8 page

google app engine / retreive the UTF-8 page


google app engine
how to use urlfetch to get the UTF-8 page

google app engine 에서 UTF-8 page 를 가져올 때


        result = urlfetch.fetch(url,
                    method=urlfetch.GET,
                    headers=header,
                    deadline=60
                )
        
        
        logger.debug(result.status_code)

       
        if result.status_code == 200:
            dataRetrieved = result.content.decode('utf-8')    # utf-8

References

  1. https://code.google.com/p/googleappengine/issues/detail?id=376

[컴][c/c++] c++ 함수 포인터의 사용법

static non-static function pointer / c/c++ 함수 포인터 / c++ 함수 포인터 / how to use c++ function pointer

function pointer 를 보다 보니, c++ 의 function pointer 가 c 와 조금 다른 모습이 있다. 자세한 사항은 ref.1 을 참고하면 된다. 여기서는 실제로 어떻게 사용하는지에 중점을 두고 이야기를 해보자.

c++ 에서 static function 과 non-static function 에 대한 declare 하는 방법이 조금 다르다.

declaration

  • non-static : class 의 이름을 명시해 줘야 하고,
  • static : 기존의 c 에서의 function pointer 와 같은 방법으로 선언하게 된다.

invocation

  • non-static : 호출시에도 instance를 통해서 호출하는 모습을 띠며,
  • static : c 에서 처럼 기존의 함수를 호출하듯이 호출하면 된다.

자세한 사항은 아래 예제를 보면서 확인하도록 하자.

/**
 * Main
 */

class A{
public :
  typedef void (A::*functionPointer)();

  functionPointer vvtable[1];
  functionPointer *vptr;

  virtual void test1(){
    std::cout << "test1" << std::endl;
    return;
  }
  static void test3(){
      std::cout << "test3" << std::endl;
      return;
    }


  A(){
    vvtable[0] = &A::test1;
    vptr = &vvtable[0];
    (this->*vvtable[0])();


  }

  virtual ~A() {}
};



typedef void (A::*fp)(); // non-static
typedef void (*fp2)(); // static

int main()
{

  A *aa = new A;

  fp f = &A::test1;
  (aa->*f)(); // call the function

  A::test3();
  fp2 f2 = &A::test3;
  f2(); // call the function



}



References

  1. http://www.newty.de/fpt/fpt.html#defi

[컴][c/c++] virtual function 의 dynamic binding 동작

virtual function / vtable / 다이내믹 바인딩 / 가상함수


Dynamic binding

compiler 가 static table 을 만든다.(static variable 이 되는 것과 비슷하다.) non-inline virtual function 을 정의한 .cpp 를 compiler 가 compile 하면서 이 v-table 을 생성하게 된다. 정의된 class 에 대해 v-table 을 만들고, __vptr 을 set 하는 과정은 아래와 같다.
vtable 생성 및 __vptr 초기화 과정
1. vtable 을 만든다. : .cpp 파일을 보면서 만드는 것이기 때문에, class 마다 생성된다. instance 가 만들어질 때마다 생성되는 것이 아니다. code 로 말하자면 base class 마다 function pointer table(static table) 을 하나씩 추가 해 주는 것이다. 예제는 ref. 2 를 참고하자.
2. class 에 __vptr 을 추가한다.(base class 에서만)
3. compiler 가 contructor 에서 각 instance 의 __vptr 을 초기화 시켜준다.
derived class 에서는 2번째 과정을 하지 않는다. 왜냐하면, 당연한 소리겠지만, base class 에서 __vptr 을 이미 추가 해 놓은 상황이어서, 자동으로 상속되기 때문에 따로 만들 필요가 없다.

참고로, __vptr 은 base class 에 만들어지게 되고, 상속받은 class(derived class) 도 자연히 상속을 받게 되어있지만, __vptr 은 instance 가 생성될 때 set 이 되기 때문에 각각의 instance 의 __vptr 은 다른 값이 되는 것이다.

실제 virtual function 이 호출되면, __vptr 이 가리키는 vtable 에서 호출을 요청한 function 을 찾고, 그 function pointer 를 이용하게 된다. c++ 에서 function pointer 의 syntax 를 확인하려면, 여기를 참고하자.

ref. 2 에 나온 Pseudocode 를 참고하면 아래와 같다.


References

  1. http://minjang.egloos.com/2934460
  2. http://isocpp.org/wiki/faq/virtual-functions#dyn-binding2
  3. http://www.newty.de/fpt/fpt.html#defi

[컴][파이썬] 파이썬에서 물음표 연산자와 같은 표현식

question operation on python / tenary conditional operator / expression


c 에서 물음표로 된 연산자가 있다. 그것을 python 에서 어떻게 표현할까 찾아보니, ref. 1 에 답변이 잘 되어 있었다. 여기서는 정리 차원에서 적어놓는다.

syntax in C/C++
condition ? true : false
for example :
   result = a > b ? a : b

syntax in Python
condition if True else False
for example:
  result = a if a>b else b

References

  1. http://stackoverflow.com/questions/3091316/python-conditional-ternary-operator-for-assignments



[컴][안드로이드] Android 의 View 에서 onMeasure 와 onLayout 의 의미

android view 에서 onMeasure / onLayout 작성하는 방법 , onMeasure , onLayout, how to write / custome layout 에서 onMeasure 와 onLayout 에 어떤 코드를 넣어야 하는가.

 

화면 구성하는 2가지의 pass 를 수행하게 된다. 순서는 아래와 같다.
  1. Measure pass
  2. Layout Pass
Measure 는 size(크기) 와 관련된 pass 이고, layout 은 좌표와 관련된 pass 라고 생각하면 된다. 그렇기 때문에 size 를 알아야 사용할 수 있는 좌표의 범위를 정할 수 있기 때문에 어쩌면 size 가 정해지고 나서 좌표를 정하는 것이 당연한 것일지 모른다.

measure vs onMeasure()

measure -> onMeasure()
layout -> onLayout()
View.java
measure 나 layout 이나 호출을 하는 모양새는 비슷하다. 모두 measure/layout 을 호출하고 그 내부에서 다시 onMeasure()/onLayout() 을 호출하고 있다.

measure() 내부에서 onMeasure() 를 호출한다. 이것을 design 관점에서 본다면, measure 는 필수적으로 수행돼야 하는 부분들을 모아놓은 것이고, 그 중에 override 를 해야 하거나, 할 수 있는 것들을 onMeasure() 로 분리해 놓은 듯이 보인다.

 

onMeasure()

View 는 layout 안에서 너비(width) 나 높이(height) 가 각 View 마다 자신의 값을 가질 수 있다. 그래서 View 는 자신의 width 와 height 의 값을 가지고 있다. 이것이 member variable 인 mMeasuredWidth / mMeasuredHeight 이다.

그래서, 기본적으로 이 mMeasuredWidth / mMeasuredHeight 이 set 돼야 한다.
View 는 그래서
View.measure() >> View.onMeasure() >> View.setMeasuredDimesion()
를 호출해서 이 작업을 한다.

그런데 우리가 customView 를 만들 때는 이 onMeasure() 를 override 하게 된다. 그러면 setMeausredDimesion() 이 호출이 안되기 때문에 우리가 만든 customView 의 onMeasure() 에서 setMeasuredDimension() 을 호출해 줘서 mMeasuredWidth / mMeasuredHeight 을 설정해야 한다.

그러면 onMeasure() 에서 할 일은 onMeasure() 를 가지고 있는 class 의 width 와 height 를 설정 해 주는 일을 한다고 보면 된다. View 를 extends 했다면 view 의 width 와 height 를 설정해 주는 작업을 onMeasure() 에 작성하면 되고, layout 을 extends 했다면, layout 의 width와 height 를 작성하는 코드를 만들면 된다.

간단히 얘기하면, size 계산(measure)해서 set 까지 해 주는 것이다.


onLayout()

FrameLayout 를 보자. FrameLayout 는 ViewGroup 이다.
ViewGroup.layout() >> View.layout() >> View.onLayout()
gravity 가 있다면 gravity 에 따라서 위치가 달라질 것이다. 그렇기 때문에 gravity 설정과 관련된 계산도 onLayout 에서 해준다.

그리고 ViewGroup() 인 경우에는 그 안에 여러 child View 들을 가지고 있다. 이 child view 들은 또 ViewGroup() 일 수도, 그냥 View 일 수도 있다. 그렇기 때문에 childView.layout() 을 호출해서 자신의 child 에게 layout 을 하라고 한다.

ViewGroup 은 자신이 가지고 있는 child View 들이 어떤 식으로 배치(layout) 되는 지를 결정해야 한다. 이런 결정은 결국 onLayout() 에서 child View 들의 구역(region) 을 정해주는 것으로 가능하다.

그러므로 현재 View 의 onLayout() 에서는 child 에게 그려지는 범위까지만 알려주면 된다. 그러면 child 는 그 범위를 자신의 범위로 인식하고 그 범위에 따른 상대적인 좌표를 계산하게 된다.
ViewGroup.layout() >> View.layout() >> View.onLayout() : empty >> ViewGroup.onLayout() : empty >> inherited class' onLayout()
View.layout() 에서 setFrame() 함수를 통해 View의 left, top, right, bottom 을 set 한다. 각 View 에서 이렇게 layout() 을 호출하기 때문에 각 View 가 setFrame() 을 호출한다고 보면 된다.
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;

Sample code[ref. 2]

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
        } else if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Height must have an exact value or MATCH_PARENT");
        }

        int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
        int panelHeight = mPanelHeight;

        final int childCount = getChildCount();

        if (childCount > 2) {
            Log.e(TAG, "onMeasure: More than two child views are not supported.");
        } else if (getChildAt(1).getVisibility() == GONE) {
            panelHeight = 0;
        }

        // We'll find the current one below.
        mSlideableView = null;
        mCanSlide = false;

  /**
   namh
   
   <core>
   for (int i = 0; i < childCount; i++)
    child.measure(childWidthSpec, childHeightSpec);
   </core>
   */
        // First pass. Measure based on child LayoutParams width/height.
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            int height = layoutHeight;
            if (child.getVisibility() == GONE) {
                lp.dimWhenOffset = false;
                continue;
            }

            if (i == 1) {
                lp.slideable = true;
                lp.dimWhenOffset = true;
                mSlideableView = child;
                mCanSlide = true;
            } else {
                height -= panelHeight;
            }

            int childWidthSpec;
            if (lp.width == LayoutParams.WRAP_CONTENT) {
                childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
            } else if (lp.width == LayoutParams.MATCH_PARENT) {
                childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
            } else {
                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
            }

            int childHeightSpec;
            if (lp.height == LayoutParams.WRAP_CONTENT) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
            } else if (lp.height == LayoutParams.MATCH_PARENT) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
            } else {
                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
            }

            child.measure(childWidthSpec, childHeightSpec);
        }

        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int paddingLeft = getPaddingLeft();
        final int paddingTop = getPaddingTop();

        final int childCount = getChildCount();
        int yStart = paddingTop;
        int nextYStart = yStart;

        if (mFirstLayout) {
            mSlideOffset = mCanSlide && mPreservedExpandedState ? 0.f : 1.f;
        }

        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);

            if (child.getVisibility() == GONE) {
                continue;
            }

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            int childHeight = child.getMeasuredHeight();

            if (lp.slideable) {
                mSlideRange = childHeight - mPanelHeight;
                yStart += (int) (mSlideRange * mSlideOffset);
            } else {
                yStart = nextYStart;
            }

            final int childTop = yStart;
            final int childBottom = childTop + childHeight;
            final int childLeft = paddingLeft;
            final int childRight = childLeft + child.getMeasuredWidth();
            child.layout(childLeft, childTop, childRight, childBottom);

            nextYStart += child.getHeight();
        }

        if (mFirstLayout) {
            updateObscuredViewVisibility();
        }

        mFirstLayout = false;
    }



References

  1. CustomLayout, 33:24
  2. SlidingUpPanelLayout.java