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
간만에 블로깅을 하면서, 옛날에 설정해놨던 syntax highlighter관련 코드들이 스킨 변경으로 날라간걸 알게 되었다.


간만에 다시 설정하려고 하다가 CDN이 없을까 검색해 봤는데

이미 고마운 분이 간단하게 적용할 수 있는 스크립트를 제공하고 있었다.


적용 방법은 아래 주소를  참조.

http://kay.starian.kr/22


직접 적용을 원한다면,

Syntax highlighter 주소 : http://alexgorbatchev.com/SyntaxHighlighter/


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

참고 : 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만 보이는 것을 알 수 있다.

디바이스 오리엔테이션:
http://bunhere.github.com/git-study/device/orientation/orientation.html
http://bunhere.github.com/git-study/device/orientation/motion.html

HTML5 Game Benchmarks
http://bunhere.github.com/HTML5-Game-Benchmarks/

media query
http://bunhere.github.io/html-study/mediaquery.html


아무 생각없이 아래와 같은 CSS를 줬는데 동작하지 않아 대략 난감.

body {
    width: 480px;
    text-align: center;
    margin-left: 0;
    margin-top: 0;
}
 
한참을 헤매다 보니, HTML5로 동작하도록 <doctype html> 태그를 준 경우와 안 준 경우에서 차이가 발생했다.
찾아보니 아래와 같은 글을 발견
http://www.webmasterworld.com/html/3533864.htm 

자세한 이유는 더 분석해 봐야 할 것 같다.
일단 이유도 모르고 아래를 추가하니, 문제가 없어졌다.
h1, p { margin: 0px; }
 


웹으로 간단한 프레젠테이션을 만들려고 했더니, html 태그를 쓰는게 무척 귀찮다는 걸 깨달았다.
물론 괜찮은 자바스크립트 유틸리티들이 있으면 쉽게 할 수 있겠지만, 원하는건 메모장 펴놓고 직접 고치는 거였는데...

xmp라는 태그가 있었으나, 해당 태그는 표준에서 제외되었다는 사실을 알았다.
https://www.w3.org/Bugs/Public/show_bug.cgi?id=12235

<pre plaintext=yes>...</pre> 와 같은 방법으로 지원하면 안되는건가? :(


C++, new
작년에 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;
}

  1. 몽상귀 2012.02.16 17:36

    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
자꾸 까먹어서 인터넷 검색을 하는게 싫어서 정리합니다 -_-;

SHELL 명령어

.tables : 테이블 목록을 보여준다.

.schema [table_name] : CREATE문을 보여준다.


SQL 명령어

select * from sqlite_master;
:

+ Recent posts