C++11에 대한 개인적인 스터디 글들입니다.

<개인적으로 공부한 내용들로, 내용이 완벽하지 않을 수 있습니다. 부족한 부분/틀린 부분에 대한 Comment 환영합니다.>


* [C++11] Type Inference : auto

* [C++11] unique_ptr

* [C++11] Variadic template

* [C++11] rvalue reference

* [C++11] Move semantics

* [C++11] Range based for loop


<계속 추가 예정입니다만. 언제 될지는 미정입니다.>


GCC 버전별 C++0x/C++11 지원 현황 : 링크

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

[C++11] unique_ptr  (7) 2013.11.01
[C++11] Type Inference: auto  (4) 2013.11.01
c++11 스터디(목차)  (0) 2013.11.01
constructor/destructor에서 virtual method의 호출  (0) 2013.02.27
GCC 옵션 : version script  (0) 2012.08.14
[C++] new는 null을 return하는가?  (1) 2012.01.17
Posted by 소혼
TAG C++11

댓글을 달아 주세요

virtual키워드를 사용해 child 객체의 메소드들을 호출할 수 있다는 것은 C++을 공부한 사람이라면 다들 알고 있는 사항이다.

예를 들어, 아래의 코드에서는 child의 call method가 호출된다.

### c++

class parent {

public: 

    virtual void call();

};

class child : public parent {

public:

    void call();

};

int main()

{

    parent* p = new child;

    p->call(); // child의 call이 호출됨

}



그렇다면 child의 instance는 virtual로 선언된 메소드들에 대해서 항상 child를 호출하는가?

오늘 그렇지 않다는 것을 배웠다.


아래 예제를 보자.

### c++

#include <stdio.h>

static void externalCall();

class A
{
public:
    A() {
        printf("In Constructor A\n");
        call();
    }
    virtual ~A() {
        printf("In Destructor A\n");
        call();
        externalCall();
    }
    virtual void call() {
        printf("    Call A is called\n");
    }
    void callFromA() {
        printf(" > In %s \n", __func__);
        call();
    }
};

class B : public A
{
public:
    B() {
        printf("In Constructor B\n");
        call();
    }
    ~B() {
        printf("In Destructor B\n");
        call();
        externalCall();
    }
    void call() {
        printf("    Call B is called\n");
    }
};

static A* global;

static void externalCall()
{
    printf(" > In %s \n", __func__);
    global->call();
}

int main()
{
    A* local = new B;
    printf("In %s \n", __func__);
    local->call();
    local->callFromA();

    global = local;
    externalCall();

    delete local;
}



위 예제를 실행해보면 재밌는 결과를 얻을 수 있다.

In Constructor A ---- 1
    Call A is called
In Constructor B
    Call B is called
In main  ---- 2
    Call B is called
 > In callFromA
    Call B is called
 > In externalCall
    Call B is called
In Destructor B ---- 3
    Call B is called
 > In externalCall
    Call B is called
In Destructor A
    Call A is called
 > In externalCall
    Call A is called


1. 실행 결과에서 먼저 생성자의 호출 순서를 알 수 있다.

생성자의 경우 부모클래스(A)의 생성자가 호출된 후, 자식 클래스(B)의 생성자가 호출된다.

이 때, 자식 클래스의 생성자가 호출되기 이전에 부른 call method는 부모 클래스의 method가 호출됨을 알 수 있다.


2. main에서는 예측한 것과 같이 자식 클래스(B)의 method만이 호출됨을 알 수 있다.

설령, 부모클래스의 메소드를 거쳐서 호출하더라도(callFromA) 자식 클래스의 인스턴스이기 때문에 자식 클래스의 메소드가 호출된다.


3. destructor의 호출 순서는 생성자의 경우와 반대로 자식 클래스의 소멸자 -> 부모클래스의 소멸자 순으로 불린다.

이 때, 자식 클래스의 소멸자 안에서 호출한 call method는 자식 클래스(B)의 메소드가 불린 반면,

부모 클래스(A)의 소멸자 안에서는 자식 클래스(B)의 call method가 아닌, 부모 클래스(A)의 call method가 불린 것을 알 수 있다.


externalCall의 결과만 보면 자식 클래스(B)의 소멸자에서 불릴때와 부모클래스(A)의 소멸자에서 불릴때 다른 메소드가 불리게 된다는 것을 알 수 있다.

소멸자가 부른 외부 함수(또는 다른 클래스의 함수)가 이를 모르고 호출할 경우, 의도하지 않은 동작을 할 수도 있기 때문에,

소멸자가 호출하는 함수가 다시 자신의 메소드를 호출하지 않도록 주의할 필요가 있을 것 같다.


PS>

쓰고 보니 이미 Effective C++에서 다루고 있는 내용이었다.

다시 읽어봐야겠다. ㅠ_ㅠ


http://www.artima.com/cppsource/nevercall.html

Posted by 소혼

댓글을 달아 주세요

참고 : http://korea.gnu.org/manual/release/ld/ld-sjp/ld-ko_2.html
참고2: http://studyfoss.egloos.com/5254916
참고3: http://stackoverflow.com/questions/8129782/version-script-and-hidden-visibility

gcc 옵션 중 version script라는 게 있다는 사실을 알았다.

정확히는 ld 옵션이기 때문에 gcc에서 옵션을 줄 때는

-Wl,--version-script=파일 경로

의 형태를 가져야 한다.

참고2에서는 버전 관리를 위해 사용했으나,
버전 관리 뿐 아니라 심볼 개수를 줄이는 용도로도 활용이 가능한가 보다.

예컨데,

// t.c

int __attribute__((visibility("default"))) foo() { return 1; }
int bar() { return 2; }
int __attribute__((visibility("default"))) exported() { return 3; }

// t.lds

{
  global
: exported;
  local
: *;
};


gcc t
.c -Wl,--version-script=t.lds -fPIC -shared -o t.so && nm -D t.so
                 w _Jv_RegisterClasses
                 w __cxa_finalize
                 w __gmon_start__
00000000000004f2 T exported

visibility가 default인 값은 두개지만, 그중 exported만 보이는 것을 알 수 있다.

Posted by 소혼
TAG gcc, 옵션

댓글을 달아 주세요

작년에 malloc vs calloc이라는 글을 적었습니다.
그때는 급작스런 궁금증때문에 인터넷 검색+발번역을 했는데,
이번에는 new에 대해 신경쓰지 못했던 부분을 알게되었습니다.

흔히, new 나 malloc으로 메모리를 할당받고 난 후, 제대로 메모리가 할당되었는지 체크를 하지않는 경우가 많습니다.
하지만, 메모리가 부족한 상황은 얼마든지 나올 수 있으므로 체크를 해야 맞겠죠.

그렇다면, 어떻게 체크해야 할까요?
임베디드의 세상에서 malloc으로 메모리를 할당받은 후에는 null인지 확인하는 것이 보편적이라는 이야기를 들었습니다.

그렇다면 new는?
C++을 배울때 제대로 공부하신 분들은 이 질문의 답을 정확히 알것입니다.
네, new 는 0을 반환하지 않습니다. 일부러 그렇게 만들지 않는한 말이죠.(오퍼레이터 오버로딩)
대신 bad_alloc exception을 발생시킵니다.
따라서, 메모리할당 여부를 굳이 확인하려면, 아래와 같이 처리해야 합니다. (예제소스)
// bad_alloc example
#include <iostream>
#include <new>
using namespace std;

int main () {
  try
  {
    int* myarray= new int[10000];
  }
  catch (bad_alloc& ba)
  {
    cerr << "bad_alloc caught: " << ba.what() << endl;
  }
  return 0;
}

Posted by 소혼
TAG C++, new

댓글을 달아 주세요

  1. 몽상귀 2012.02.16 17:36 Address Modify/Delete Reply

    Note that you can specify that you want new to return 0 instead of throwing std::bad_alloc using the std::nothrow parameter:

    SomeType *p = new(std::nothrow) SomeType;

    http://stackoverflow.com/questions/550451/will-new-return-null-in-any-case

    즉, new 연산자를 수정하는 행위 없이 호출 할 때 저렇게 하면 된답니다. try-catch 쓰기 싫으시면 ..:D







오픈소스에 버그를 하나 등록했는데 아래와 같은 Comment를 받았습니다.


"this does not go to the .rodata section in the binary;

use static const char foo[] instead."

 이게 무슨 소린가 하고, 확인을 하기 위해 간단한 프로그램을 작성해보았습니다.



### c++

/* file: constchar.cpp
*
* gcc -S -O0 constchar.cpp -DCONST_POINTER
*/
#if defined(CONST_POINTER)
static const char* name = "hello";
#elif defined(CONST_ARRAY)
static const char name[] = "hello";
#else
static const char* const name = "hello";
#endif

int main()
{
return 0;
}


확인해보니 리뷰 comment대로

static const char* name = "Hello"; (이하 const_pointer)와 static const char name[] = "Hello"; (이하 const_array)

static const char* const name = "Hello"; (이하 const_pointer_const)

이 셋이 서로 다른 코드를 생성하는 것을 알 수 있었습니다.




먼저 .text 섹션을 보겠습니다.

main함수가 동일하기 때문에 위치만 다를뿐 동일합니다.

세 경우 모두, .rodata 섹션에 Hello 가 들어있습니다.

하지만 name(_ZL4name) 심볼의 경우,

const_pointer.s의 경우만 .data 섹션에 있고, const_array.s와 const_pointer_const.s의 경우에는 .rodata 섹션에 같이 있습니다.
생각해보면, const_pointer.s는 name의 값을 바꿀 수 있으니 당연히 .data 섹션에 변수로서 존재해야 합니다.
예를 들어 아래는 정상적인 코드입니다. static const char* name = "Hello";
name = "changed"; 하지만 아래는 컴파일 에러가 납니다. static const char name[] = "Hello";
name = "changed"; 따라서 변경 불가능한 문자열을 만들려고 한다면, const char [] 또는 const char* const를 사용해야 합니다.

그럼 const_array.s와 const_pointer_const.s의 차이는 뭘까요?

const_array.s를 보시면 LC0 label이 없는 것을 알 수 있습니다.

const_array.s의 경우만 name이 직접 Hello를 가르키고 있습니다.

(결론)
상수형 문자열을 쓰고자 한다면 static const char foo[] = "XXX"; 형태가 낫습니다.

참고로 아래 링크는 C언어의 변수 선언시 저장되는 영역에 관한 것입니다.
http://wwww7.com/bbs/zboard.php?id=Study&page=1&sn1=&divpage=1&category=3&sn=off&ss=on&sc=on&select_arrange=headnum&desc=desc&no=57


'프로그래밍 언어 > C/C++' 카테고리의 다른 글

GCC 옵션 : version script  (0) 2012.08.14
[C++] new는 null을 return하는가?  (1) 2012.01.17
static const char* vs static const char []  (0) 2012.01.04
우분투에서 ccache로 컴파일을 빠르게...  (0) 2011.08.31
POD vs non POD  (0) 2011.08.07
memwatch  (0) 2011.05.24
Posted by 소혼

댓글을 달아 주세요



코딩/실행/디버깅의 전환은 매우 빠르게 이뤄져야 합니다.
놀지 말고 일하라! 가 아니라. 흐름을 유지하면서 개발하는게 좋다고 생각하기 때문입니다.

그래서 우연히 ccache란 것을 알게 되어 쓰기로 마음 먹었습니다.

설치는 간단합니다.
apt-get install ccache

사용법도 간단합니다. PATH에 /usr/lib/ccache를 걸어주면 됩니다.
export PATH=/usr/lib/ccache:$PATH

그럼 컴파일 시간을 비교해보겠습니다.
WebKit/Efl 을 다운로드 받아 빌드해서 나온 시간입니다.
각 빌드는 빌드 결과물들을 모두 제거하고 빌드한 것입니다.

1. ccache 없이 풀빌드

real 30m38.772s
user 50m25.953s
sys 5m55.686s

2. ccache 설치후 첫 풀빌드
real 31m42.091s
user 51m54.923s
sys 6m30.928s

3. ccache 설치 후 두번째 풀빌드 
real 6m19.574s
user 5m28.033s

sys 3m57.867s

상상할수 없이 빨라졌습니다.
왜 빨라진걸까요? 컴퓨터 세계에 마법은 존재하지 않습니다.
ccache는 사용자의 디렉토리에 .ccache라는 폴더를 생성하여 object 파일을 해싱하여 저장해두고 있습니다.
만약 다른 디렉토리에 ccache를 저장하고 싶다면, 아래와 같은 환경 변수를 추가로 설정해주시면 됩니다.
export CCACHE_DIR=/development/ryuan/ccache

(일반적으로는 쓸 일이 없지만, 작은 SSD를 사용중이라면 고려해볼 수 있습니다.)


# ls ~/.ccache/

0  1  2  3  4  5  6  7  8  9  CACHEDIR.TAG  a  b  c  d  e  f  stats

preprocessor를 거친 소스코드를 해슁하여 해당 키와 겹치는 object코드가 있으면 컴파일을 하지 않고 해당 object를 그냥 반환하는 방식입니다
2번 과정에서 보시는 것처럼 키가 없는 경우에는 약간의 시간이 더 걸리지만 그렇게 많은 시간은 아닙니다.


'프로그래밍 언어 > C/C++' 카테고리의 다른 글

[C++] new는 null을 return하는가?  (1) 2012.01.17
static const char* vs static const char []  (0) 2012.01.04
우분투에서 ccache로 컴파일을 빠르게...  (0) 2011.08.31
POD vs non POD  (0) 2011.08.07
memwatch  (0) 2011.05.24
GCC옵션: finstrument-functions  (0) 2011.05.24
Posted by 소혼

댓글을 달아 주세요

참고자료 : http://gpgstudy.com/forum/viewtopic.php?t=10148&view=previous
참고자료2 : http://1stpasa.tistory.com/entry/PODPlain-Old-Data-Non-POD
참고자료3 : http://stackoverflow.com/questions/146452/what-are-pod-types-in-c

POD (Plain Old Data)

메모리상에 연속적으로 나열되는 단순한 형태의 자료구조를 말한다.
C에서 사용하던 built-in type과  built-in type을 묶어서 만들어진 struct 들이 여기에 속한다.

class의 경우에는 가상함수가 있거나, 소멸자가 있거나, 할당자가 있으면 POD가 될 수 없다.

POD에 해당하는 자료구조는 memcpy를 통해 복사하는 것이 가능하다.
따라서 간단히 패킷에 실어보낼수도 있을 것이다.

버그질라에서 이런 용어를 쓰길래 찾아봤는데 왜 찾아봤던건지 기억이 안나네 ;;
 

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

static const char* vs static const char []  (0) 2012.01.04
우분투에서 ccache로 컴파일을 빠르게...  (0) 2011.08.31
POD vs non POD  (0) 2011.08.07
memwatch  (0) 2011.05.24
GCC옵션: finstrument-functions  (0) 2011.05.24
linker 관련 링크  (0) 2011.04.15
Posted by 소혼
TAG Pod

댓글을 달아 주세요

메모리 누수를 측정하는 툴
다운로드 URL: http://www.linkdata.se/sourcecode/memwatch/

http://blog.naver.com/PostView.nhn?blogId=lowcarpet&logNo=70029068932&redirect=Dlog&widgetTypeCall=true

간단한 예제로 실험한 결과
memwatch.log
  1 
  2 ============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============
  3 
  4 Started at Tue May 24 22:08:35 2011
  5 
  6 Modes: __STDC__ 64-bit mwDWORD==(unsigned long)
  7 mwROUNDALLOC==8 sizeof(mwData)==32 mwDataSize==32
  8 
  9 
 10 Stopped at Tue May 24 22:08:35 2011
 11 
 12 unfreed: <1> main.c(6), 30 bytes at 0x8a221d0   {FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE
    FE ................}
 13 
 14 Memory usage statistics (global):
 15  N)umber of allocations made: 1
 16  L)argest memory usage      : 30
 17  T)otal of all alloc() calls: 30
 18  U)nfreed bytes totals      : 30 

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

우분투에서 ccache로 컴파일을 빠르게...  (0) 2011.08.31
POD vs non POD  (0) 2011.08.07
memwatch  (0) 2011.05.24
GCC옵션: finstrument-functions  (0) 2011.05.24
linker 관련 링크  (0) 2011.04.15
calloc vs malloc  (7) 2011.04.06
Posted by 소혼

댓글을 달아 주세요

추가 조사 : -finstrument-functions-exclude-file-list
 

instrument-functions 옵션은 함수의 시작과 끝에 다른 함수를 삽입해주는 옵션입니다.
용도는 다양할 것 같지만, 디버깅이 어려운 환경 - 예를 들어 임베디드, 멀티 프로세스 환경, 서버-클라이언트 구조 등에서 큰 도움이 될 것 같습니다.
그 외 많은 프로파일링 툴이 이것을 사용하여 나름의 기능을 구현하는 것 같습니다.

사용 방법은 무척 간단합니다.



__cyg_profile_func_enter 와 __cyg_profile_func_exit는 instrument 옵션이 켜졌을 때 gcc가 연결해주는 함수입니다.
이 함수들은 다른 함수들과 다르게  no_instrument_function이라는 attribute를 가지고 있습니다.
no_instrument_function는 이 함수들에는  __cyg_profile_func_enter와 __cyg_profile_func_exit를 삽입하지 말라는 뜻입니다.

간단한 예제를 짜 보았습니다.

 
이 파일을 gcc로 컴파일하고 실행하면 아래와 같습니다.
# ./a.out 
## this is main()
## this is main() -- 32 

instrument-functions 옵션을 주고 컴파일해보겠습니다.
# gcc -c main.c -finstrument-functions -g
# gcc -c test.c -finstrument-functions -g
# gcc -o b.out main.o test.o
# ./b.out 
> Enter 0x8048561
 ## this is main()
> Enter 0x804850e
> Enter 0x80484ca
> Enter 0x8048454
> Leave 0x8048454
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x804848f
> Leave 0x804848f
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x8048454
> Leave 0x8048454
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x804848f
> Leave 0x804848f
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x8048454
> Leave 0x8048454
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x804848f
> Leave 0x804848f
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x8048454
> Leave 0x8048454
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x804848f
> Leave 0x804848f
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x8048454
> Leave 0x8048454
> Leave 0x80484ca
> Enter 0x80484ca
> Enter 0x804848f
> Leave 0x804848f
> Leave 0x80484ca
> Leave 0x804850e
> Enter 0x8048454
> Leave 0x8048454
 ## this is main() -- 32
> Leave 0x8048561
 
함수의 시작과 끝에 그 함수의 위치정보가 출력됩니다.
이 정보를 이해할 수 있는 값으로 바꾸어 주는 툴이 있습니다. addr2line입니다.

# addr2line 0x804850e -e b.out -f
a
/workspace/study/c/ins/main.c:23 

이 툴을 이용해서 위 코드를 python으로 변환해보았습니다.

# python converter.py test log
[0x8048561]  > main at main.c:31
 ## this is main()


[0x804850e]    > a at main.c:23
[0x80484ca]      > b at main.c:15
[0x8048454]        > c at main.c:5
[0x80484ca]      > b at main.c:15
[0x804848f]        > d at main.c:10
[0x80484ca]      > b at main.c:15
[0x8048454]        > c at main.c:5
[0x80484ca]      > b at main.c:15
[0x804848f]        > d at main.c:10
[0x80484ca]      > b at main.c:15
[0x8048454]        > c at main.c:5
[0x80484ca]      > b at main.c:15
[0x804848f]        > d at main.c:10
[0x80484ca]      > b at main.c:15
[0x8048454]        > c at main.c:5
[0x80484ca]      > b at main.c:15
[0x804848f]        > d at main.c:10
[0x80484ca]      > b at main.c:15
[0x8048454]        > c at main.c:5
[0x80484ca]      > b at main.c:15
[0x804848f]        > d at main.c:10
[0x8048454]    > c at main.c:5
 ## this is main() -- 32

실제 프로젝트로 해봐야 피부에 와닿을 것 같습니다.
 

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

POD vs non POD  (0) 2011.08.07
memwatch  (0) 2011.05.24
GCC옵션: finstrument-functions  (0) 2011.05.24
linker 관련 링크  (0) 2011.04.15
calloc vs malloc  (7) 2011.04.06
[C언어] a - b < 0 vs. a < b  (0) 2010.10.25
Posted by 소혼
TAG gcc, 옵션

댓글을 달아 주세요

ld 옵션에 관하여.
http://korea.gnu.org/manual/release/ld/ld-sjp/ld-ko_toc.html

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

memwatch  (0) 2011.05.24
GCC옵션: finstrument-functions  (0) 2011.05.24
linker 관련 링크  (0) 2011.04.15
calloc vs malloc  (7) 2011.04.06
[C언어] a - b < 0 vs. a < b  (0) 2010.10.25
C로 수행시간 체크하기  (0) 2010.09.30
Posted by 소혼

댓글을 달아 주세요