'프로그래밍 언어/C/C++'에 해당되는 글 29건

  1. 2016.10.18 [읽은 글] const correctness
  2. 2015.05.29 [C++11] std::function의 성능
  3. 2013.12.05 GCC options
  4. 2013.11.13 [C++11] Range based for loop (4)
  5. 2013.11.10 [C++11] Move semantics (4)
  6. 2013.11.07 [c++11] rvalue reference (1)
  7. 2013.11.06 [C++11] Variadic template
  8. 2013.11.01 [C++11] unique_ptr (7)
  9. 2013.11.01 [C++11] Type Inference: auto (4)
  10. 2013.11.01 c++11 스터디(목차)

https://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/

https://herbsutter.com/2013/05/24/gotw-6b-const-correctness-part-2/

https://herbsutter.com/2013/05/28/gotw-6b-solution-const-correctness-part-2/


* 번역이 아니라 이해하고 정리한 내용입니다. 따라서 원 글의 의도가 전달되지 않을 수 있으며, 수정 될 수 있습니다.


[ ] https://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/


1. shared variable

Shared variable이란 하나 이상의 thread에서 동시에 접근할 수 있는 변수를 말한다.


2. shared variable의 관점에서 const 나 mutable이란?

const member function은 다음 두가지 중 하나를 반드시 만족해야 한다. (절대 공유되지 않는다는 가정이 있지 않는 한)

 - 진짜로 const(truly physically/bitwise const). 다시 말해 객체의 어떤 데이터에도 write하지 않아야 한다.

 - 내부적으로 동기화되어서 (예를 들어 mutex, atomic<> 등으로) 동시에 호출되더라도 문제가 없어야 한다.


비슷하게, 멤버 변수에 mutable 키워드를 쓴다는 것은 그 변수가 쓸 쑤 있지만 논리적으로는 const(writable but logically const) 임을 의미한다.

- 논리적으로 const란 여러 동시성 (const) 연산들로부터 안전하다는 의미이다.

- mutable이 붙어있다는 것은 어떤 const operation이 사실은 write할지 모른다는 뜻이고, 동시성을 갖고 읽고 쓰는데 문제가 없다는 의미이다. 따라서 mutex 나 유사한 동기화 로직 아니면 atomic<>으로 만들어야 한다.


따라서, mutex 와 mutable 을 같이 써야 한다. (또는 atomic<> 과 mutable)


3. c++98과 c++11에서 mutable과 const는 뭐가 다른가?


먼저 그전에...

이 내용을 정리하기 전에, const와 mutable에 대해 헷갈리게 했던 부분은 const_cast를 통해 수정하면 되지 왜 mutable을 써야 하지? 하는 점이었다.

예를 들면 아래 처럼...


#include <vector>

class Tile { ... };

class TileStore {
public:
Tile* getTile() const {
if (empty_tiles_.empty()) {
const_cast<TileStore*>(this)->ReserveMoreTiles();
}
// ...
return //something;
 }
void ReserveMoreTiles() {
// ...
}
private:
std::vector<Tile*> empty_tiles_;
};


먼저 아래 링크을 가져왔다.

http://stackoverflow.com/questions/11457953/const-cast-vs-mutable-any-difference


const_cast는 사실 대상 객체의 const 속성을 제거하는 것이 아니다. 대신 접근 경로(access path)상에 const 속성을 바꿔주는 것이다.

따라서 진짜 const 객체에 대하여 const_cast를 수행하는 것은 Undefined behavior를 야기할 수 있다.


  const int j = 5; // constant object
  const int *p = &j; // `p` is a const access path to `j`

  int *q = const_cast<int *>(p); // `q` is a non-const access path to `j`
  *q = 10; // UNDEFINED BEHAVIOR !!!


그럼 mutable은 뭘까? [1]

 - mutable로 지정된 멤버는 외부에 노출된 클래스의 상태(the externally visible state of the class)에 영향을 받지 않는다.

 - const 클래스의 mutable 멤버는 수정 가능하다.

 - c++은 mutable을 storage-class-specifier로 취급한다.


mutable이 단순히 상수성을 제거한다는 생각을 했는데, 중요한 포인트중 하나는 class가 const여도 된다는 것이다.

즉,

* const_cast는 애초에 다루는 객체가 const이면 안된다.

* mutable은 다루는 객체가 const여도 modifable하다.


위에 적당히 만들어본 Tile & TileStore를 아래처럼 고쳐보았다.


#include <vector>
#include <stdio.h>

class Tile { public: int i; };
class TileStore { public: Tile* getTile() const { if (empty_tiles_.empty()) { const_cast<TileStore*>(this)->ReserveMoreTiles(); }
return empty_tiles_[0]; } void ReserveMoreTiles() {
Tile* tile = new Tile(); tile->i = 10; empty_tiles_.push_back(tile); } private: std::vector<Tile*> empty_tiles_; };
int main() { const TileStore a; Tile* t = a.getTile(); printf("%d\n", t->i); return 0; }

이 동작은 undefined behavior이다. const 객체의 constness를 제거하는 로직이니까.

mutable로 empty_tiles_를 선언해야 맞는 것 같다.


결론적으로 const_cast는 위험하다! (const 객체 안쓴다고 확신할 수 있는가?)


PS. 하지만, QT 5.6으로 컴파일뿐 아니라 실행은 잘 된다. (undefined.... != crash)


3으로 다시 돌아가서....


C++98 single threaded code는 문제 없다. ( 왜 c++98 single threaded code라고 부르는지 모르겠다. )

C++98에서 우리는 const는 논리적인 const(logically const)이며, 물리적인/비트레벨의 const(phisically/bitwise)는 아니다라고 가르쳐왔다.


이제 C++11에서는 const란 read-only 또는 동시성을 고려해서 안전하게 읽을수 있음(safe to read concurrently)을 보장한다.(해야 한다.)

다시 말해 물리적인/비트레벨의 const이거나 내부적으로 동기화되어 어떠한 쓰기 동작도 concurrent한 read access들로부터 동기화되어야 한다.


요약해서,

const correctness 코드를 짜라.

const를 올바르게 사용하는 것은 올바르게 동기화된 코드를 위해 필요하다. 또 const는 그 자체로 "값을 수정하지 않겠다는" 훌륭한 문서이고 컴파일러가 더 나은 코드를 만드는 것을 도와준다.


cosnt 객체나 동작(메소드)에서 멤버를 수정해야 한다면 mutable을 mutex 또는 atomic과 함께 써라.

모든 상용 라이브러리들이 const correct하진 않다.


[ ] https://herbsutter.com/2013/05/28/gotw-6b-solution-const-correctness-part-2/


1. 함수를 선언할때 레퍼런스가 아닌 파라미터의 const는 의미 없다.


void a(const int);
void a(int); // same

void b(const int&);
void b(int&); // different

그러나 inline 함수는 선언과 정의가 같이 있으니까 적는게 의미가 있다.


2. 이항 연산자의 overload시 rhs는 const, lhs는 const가 아닌것이 좋다.

// 잘못된 예제 코드
polygon operator+( polygon& lhs, polygon& rhs ) {
auto ret = lhs;
auto last = rhs.get_num_points();
for( auto i = 0; i < last; ++i ) // concatenate
ret.add_point( rhs.get_point(i) );
return ret;
}

lhs를 ret에 복사하고 있다.

결국 내부에서 한번의 객체 복사가 이뤄져야 하는데, 이 객체가 앞서 호출된 임시객체인 것이 유리할 수 있다.

예를 들어 x = a + b + c;

a + b를 수행하면서 생긴 ret객체를 다시 lhs로 받아서 c와 더하게 된다.


즉, 아래와 같이 하는 것이 비용이 적을 가능성이 있다.

polygon operator+(polygon lhs, const polygon& rhs) {
// ...
return lhs;
}


참조

[1] http://en.cppreference.com/w/cpp/language/cv

저작자 표시
신고

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

[읽은 글] const correctness  (0) 2016.10.18
[C++11] std::function의 성능  (0) 2015.05.29
GCC options  (0) 2013.12.05
[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
Posted by 소혼

std::function의 성능이 생각보다 많이 느리다는 것을 알게 되었다.


test.cpp

ryuan@webkit:~$ g++ ./test.cpp --std=c++11 -O3 -DINTERFACE_VERSION
ryuan@webkit:~$ ./a.out
main:96] 8 elapsed
ryuan@webkit:~$ g++ ./test.cpp --std=c++11 -O3 -DINTERFACE_VERSION_NO
ryuan@webkit./a.out
main:96] 437 elapsed


못쓰겠네 -_-;

http://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction/


[Update]

Modern Effective C++ Item 5 에 따르면

std::function은 단순히 closure와 유사한 것이 아니라 모든 callable object를 담는 것으로...

추가적인 heap 메모리를 사용하는 것 같다.


위 예제를 auto로 바꿔서 테스트해봐야겠다.

저작자 표시
신고

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

[읽은 글] const correctness  (0) 2016.10.18
[C++11] std::function의 성능  (0) 2015.05.29
GCC options  (0) 2013.12.05
[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
Posted by 소혼

<< 작성중 >>

성능과 관련된 옵션들

-fno-rtti (runtime type information)

rtti는 아래와 같이 두가지 경우에 사용됩니다.

- #include <typeinfo>

typeinfo(this).name()

### c++

class type_info {
public:
    virtual ~type_info();
    bool operator==(const type_info& rhs) const;
    bool operator!=(const type_info& rhs) const;
    int before(const type_info& rhs) const;
    const char* name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
    const char* raw_name() const;
private:
    void *_m_data;
    char _m_d_name[1];
    ...
};

- dynamic_cast

성능에 영향을 줄 수 있으므로 -fno-rtti 를 주면 type_info가 생성되지 않습니다.


-Os

-Os는 O2에 -falign-functions  -falign-jumps  -falign-loops -falign-labels  -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays  -ftree-vect-loop-version 를 제거한 것과 같다.


-fprofile-generate, -fprofile-use, -fprofile-arcs


참고자료 : http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html


Linker options (-Wl, ...)

--as-needed :

http://www.ubuntu.or.kr/viewtopic.php?p=70082



신고

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

[읽은 글] const correctness  (0) 2016.10.18
[C++11] std::function의 성능  (0) 2015.05.29
GCC options  (0) 2013.12.05
[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
Posted by 소혼

목차로 가기


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


- 업데이트

 * 박진수님이 지적해주신 오타 수정


C++11 에는 새로운 형태의 for loop인 range based for loop를 지원합니다.

이미 python같은 언어에서는 지원되던 기능이기도 합니다.


python에서는 아래처럼 루프를 사용할 수 있었습니다.

### python

peoples = ['ryuan', 'yesum',  'w.third']
for p in peoples:
   print 'people :', p


이것을 c++에서 구현하려면 아래와 같이 해야 할 것입니다.


### c++

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<string> s;
    s.push_back("ryuan");
    s.push_back("yesum");
    s.push_back("w.third");

    for (vector<string>::iterator i = s.begin(); i != s.end(); ++i)
        cout << "people :" << *i << endl;

    return 0;
}


물론 auto의 등장으로 for loop는 아래처럼 간단해질 수 있습니다.

### c++

    for (auto i = s.begin(); i != s.end(); ++i)
        cout << "people :" << *i << endl;


하지만, 만약 vector대신 2차원 배열로 바꾸려고 하면 어떻게 해야 할까요?

### c++

int main()
{
    const char *s[3] = { "ryuan", "yesum", "w.third" };

    for (int i = 0; i != 3; ++i)
        cout << "people :" << s[i] << endl;

    return 0;
}


이제 range based for loop를 쓰면 아래와 같습니다.

### c++

int main()
{
    //const char *s[3] = { "ryuan", "yesum", "w.third" };
    vector<string> s;
    s.push_back("ryuan");
    s.push_back("yesum");
    s.push_back("w.third");

    for (auto i : s)
        cout << "people :" << i << endl;

    return 0;
}


vector를 쓰던, 배열을 쓰던 동일합니다.


주의할 점은 range loop의 인자 i 는 반드시 loop안에서 선언되어야 한다는 점입니다. 만약 loop밖에서 선언하고 안에서 사용하지 않는다면 아래처럼 에러가 날 것입니다.(gcc)

range_for_loop.cpp: In function ‘int main()’:
range_for_loop.cpp:10:12: error: found ‘:’ in nested-name-specifier, expected ‘::’
range_for_loop.cpp:10:10: error: ‘i’ is not a class, namespace, or enumeration
range_for_loop.cpp:10:15: error: expected ‘;’ before ‘)’ token
range_for_loop.cpp:13:5: error: expected primary-expression before ‘return’
range_for_loop.cpp:13:5: error: expected ‘;’ before ‘return’
range_for_loop.cpp:13:5: error: expected primary-expression before ‘return’
range_for_loop.cpp:13:5: error: expected ‘)’ before ‘return’


그럼 만약, 내가 만든 클래스를 range based for loop로 사용하고자 한다면 어떻게 하면 될까요?

물론 이런 경우가 흔하진 않겠지만, 간단한 class를 만들어보도록 하겠습니다.

### c++

#include <iostream>

class IntList
{
public:
    class Iterator {
    public:
        Iterator(const IntList* p, int pos)
            : m_p(p)
            , m_pos(pos)
        { }

        // Range based for loop use below methods
        bool operator!=(const Iterator& other) const { return m_pos != other.m_pos; }
        int operator*() const { return m_p->get(m_pos); }

        const Iterator operator++()
        {
            //little bit tricky
            ++m_pos;
            return *this;
        }
    private:
        const IntList* m_p;
        int m_pos;
    };

    IntList()
    {
        for (int i = 0; i < 10; ++i)
            m_arr[i] = i;
    }
   
    int get(int i) const { return m_arr[i]; }
    Iterator begin() const { return Iterator(this, 0); }
    Iterator end() const { return Iterator(this, 10); }
private:
    int m_arr[10];
};

int main()
{
    IntList list;
    for (auto i : list)
        std::cout << i << std::endl;
    return 0;

}

실제로 쓸모는 없지만, range based for loop 는 동작합니다.

결국,

begin(), end()를 제공하고, 이때 반환되는 iterator 클래스에서 operator++, operator*, operator!=을 구현하면 됩니다.








참조 : http://www.cplusplus.com/forum/beginner/99989/

참조 : http://www.cprogramming.com/c++11/c++11-ranged-for-loop.html

저작자 표시
신고

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

[C++11] std::function의 성능  (0) 2015.05.29
GCC options  (0) 2013.12.05
[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
[C++11] Variadic template  (0) 2013.11.06
Posted by 소혼
TAG C++11

목차로 가기


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


C++11에서는 Move semantics라는 개념이 도입되었습니다.


move semantics가 도입된 배경에 대해 이해하기 위해 아래 예제를 보도록 하겠습니다.

### c++

#include <iostream>
using namespace std;

class Number
{
public:
    explicit Number(int i)
        : m_number(new int(i))
    {
        cout << "Number Constructor is called(" << i << ")" << endl;
    }
    ~Number()
    {
        if (m_number)
            cout << "Number Destructor is called(" << *m_number << ")" << endl;
        delete m_number;
    }
    Number(const Number& rhs)
        : m_number(new int(*rhs.m_number))
    {
        cout << "Number copy constructor is called" << endl;
    }
       
    static void printValue(Number n) {
        cout << "print " << *n.m_number << endl;
    }

private:
    int* m_number;

};

int main()
{
    Number one(1);

    Number::printValue(one);
}

설명을 위해 의도적으로 m_number를 heap에 할당했습니다.


위 예제를 실행하면 아래와 같은 결과가 나옵니다.

Number Constructor is called(1)
Number copy constructor is called
print 1

Number Destructor is called(1)

Number Destructor is called(1)


 printValue의 인자로 넘겨주는 과정에서 한번의 복사과정이 발생하게 됩니다. 불필요한 객체를 막기 위해 printValue를 아래와 같이 바꿀 수 있습니다.

### c++

static void printValue(const Number& n) {
    cout << "print " << *n.m_number << endl;

}

핵심은 reference로 변경한 것입니다. (reference는 원본을 참조하므로 내부에서 수정을 못하도록 const를 붙여주어야 합니다.)

이제 복사 생성자(copy constructor)가 호출되지 않을 것입니다.


이제 예제를 좀 더 확장해 아래와 같은 경우를 보도록 하겠습니다.

### c++

// in main

Number x(one); // (1)

이 경우 x와 one은 별도의 객체이므로 복사 생성자가 불려야 합니다.


### c++

class Number {

    ...

    Number operator+(Number& rhs)
    {
        return Number(m_number + rhs.m_number);
    }

    ...

};


Number make_number()
{
    return Number(2);
}


//in main
Number value(make_number()); // (2)
Number sum(one + two); // (3)

value와 sum을 만들기 위해서는 모두 두번의 복사 생성자가 불립니다.

이 경우에 불리는 복사 생성자는 사실상  불필요합니다. 하지만 제거할 방법은 마땅하지 않습니다.

물론 일부 compiler에서 최적화를 지원합니다. (Return Value Optimization : RVO)

gcc 의 경우 -fno-elide-constructors 를 사용하면 이 기능을 끌 수 있습니다.


현재 예제의 경우는 간단하기 때문에 임시로 생성되는 객체들에 대한 부담이 적을 수 있습니다만, Number가 아니라 Vector와 같은 많은 리소스를 사용해야 하는 경우라면 이것은 그대로 비효율이 됩니다.


(1)과 (2), (3)에는 한가지 중요한 차이점이 있습니다.

(1)은 lvalue를 받은 경우이고, (2), (3)은 rvalue를 넘겨받은 경우라는 사실입니다.


c++11부터는 이동 생성자가 생겼습니다.

rvalue reference를 인자로 받는 새로운 생성자입니다.


위 예제에서 아래와 같이 이동 생성자를 추가하겠습니다.

### c++

    Number(Number&& rhs)
    {
        cout << "Number move constructor is called" << endl;
        m_number = rhs.m_number;
        rhs.m_number = nullptr;
    }

이동 생성자가 복사 생성자와 다른 점은 rvalue reference로 받아서 받은 rhs의 m_number를 그대로 사용한다는 점입니다.

따라서, 복사 생성자가 불렸을 때와 비교해 불필요한 메모리 할당/해제가 사라지게 됩니다.




참조 : http://stackoverflow.com/questions/3106110/what-is-move-semantics

저작자 표시
신고

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

GCC options  (0) 2013.12.05
[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
[C++11] Variadic template  (0) 2013.11.06
[C++11] unique_ptr  (7) 2013.11.01
Posted by 소혼

목차로 가기


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



이미 C++  에서는 Reference(참조자)를 지원하고 있습니다.rvalue Reference를 설명하기 전에 기존의 Reference의 예제를 잠깐 살펴보겠습니다.


### c++

#include <iostream>
using namespace std;

int main()
{
    int zero = 0;
    int& a = zero; //OK
    int& b = 0; // Compile Error
    return 0;
}


아시겠지만, Reference에 0을 할당하는 것은 불가능합니다.

예제를 컴파일 해보면 아래와 같은 에러를 볼 수 있습니다. (gcc 기준)

g++ rvalue_reference.cpp
rvalue_reference.cpp: In function ‘int main()’:
rvalue_reference.cpp:8:14: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’


에러 메시지를 번역해보자면,"int 타입의 rvalue에서 int& 타입인 non-const reference로의  잘못된 초기화" 입니다.

물론 const int& b 로 바꿔도 동작은 합니다.


여기서 핵심은

1. 0은 rvalue입니다.

2. (기존의) reference는 rvalue를 참조하지 못합니다. (const reference(&)는 rvalue도 담을순 있습니다.)


따라서 reference(&)를 lvalue reference라고 부를 수 있습니다. (물론 그동안 이렇게 부를 필요가 없었죠. rvalue reference가 나오기 전까진...)

 


lvalue 와 rvalue


이제 lvalue와 rvalue에 대해 이야기해보겠습니다.

전통적인 의미로 이것은 Left Value와 Right Value를 의미했으나(참조1),

사실상 C에서의 lvalue는 수식의 오른쪽 값이 쓰여질 수 있는 메모리 공간을 가르키는 용어(locater value)입니다.
(오른쪽 값이 rvalue를 의미하는 것은 아닙니다.)


따라서 lvalue는 반드시 left에 올 필요는 없습니다.

### c++

int x = 9;

std::string s;

int* p = 0;

int& ri = x;

x, s, p, ri 모두 lvalue입니다. 4번 라인에서 x는 오른쪽에도 존재합니다.


이제 lvalue를 다시 설명해보고자 합니다.

"lvalue란 이름은 E1 = E2 의 수식에서 E1이 (수정 가능한) lvalue 이어야 한다는 데서 기원하고 있습니다. 그러나 "locaor value"를 의미한다고 생각하는 것이 나을 것입니다."

The name "lvalue" comes originally from the assignment expression E1 = E2, in which the left operand E1 must be a (modifiable) lvalue. It is perhaps better considered as representing an object "locator value."


rvalue는 수식의 값으로써 종종 언급되었습니다.

What is sometimes called ‘‘rvalue’’ is in this International Standard described as the ‘‘value of an expression’’.


rvalue의 대표적인 예는 literal들입니다. 위 예제의 9나 0 또는 'a', "hello"는 rvalue들입니다.


아래의 예를 더 보도록 하겠습니다.

### c++
++i;
i++;

++i는 lvalue이고 i++은 rvalue입니다.


i++이 rvalue인 것을 증명하기 위해, 간단한 테스트를 해보겠습니다.

###c++

int i = 1;
int& a = ++i; // ok
int& b = i++; // compile error

4번 라인은 앞에서 봤던 것과 동일한 에러가 날 것입니다.


앞서 ++i는 lvalue인 i의 값을 증가시킨 후, i를 반환합니다. 따라서 ++i는 lvalue입니다.

반면, i++은 lvalue인 i의 값을 증가시키지만, 증가되기 전의 값을 임시로 보관하여 반환합니다.

따라서, 반환되는 값은 임시로 존재하며 수식이 끝나는 순간 사라지게 됩니다.


또 다른 예를 보겠습니다.

### c++

int i = 1;
const int& p = i;

p = 7; // compile error

p 는 lvalue이지만, const 속성때문에 rvalue인 7을 저장할 수 없습니다.


lvalue나 rvalue 모두 const 나 non-const 속성을 가질 수 있습니다.

### c++

string one("one");
const string two("two");
string three() { return "three"; }
const string four() { return "four"; }

static int s_five = 0;

int& five() { return s_five; }

int main()
{
    one;     // 변경 가능한(non-const)lvalue
    two;     // 변경 불가능한(const) lvalue
    three(); // 변경 가능한(non-const) rvalue
    four();  // 변경 불가능한(const) rvalue

    int& f = five(); // 변경 가능한(non-const)lvalue

    f = 5;

    cout << f << " equals " << s_five << endl;


    return 0;
}


앞에서 보여드린 것처럼 reference는 lvalue를 참조합니다.

따라서 reference를 반환하는 five도 lvalue입니다.


수식(expression)이 끝나도 존재하는 것을 lvalue, 수식의 종료와 함께 사라지는 임시적인 값을 rvalue라고 설명하기도 합니다.

또 다른 설명으로 수식(expression)에서 identity를 가지는 value가 lvalue, identity를 가지지 않는 value가 rvalue라고도 합니다.


여기까지가 C++ 03까지에 대한 내용입니다.


이제 rvalue reference에 대해 설명하도록 하겠습니다.

c++11에서는 rvalue reference(&&)라는 새로운 operator가 등장합니다.

### c++

int&& sum(int a, int b)
{  
    return a + b;
}

int main()
{  
    int&& r = sum(1, 2);
    cout << r << endl;
    return 0;
}

크게 필요성을 느끼기 어려운 예제입니다. 심지어 gcc에서는 warning도 납니다. 하지만 짚고 넘어갈 부분이 있습니다.


보시면 a + b의 결과가 문장(8 line)이 지나갈때까지 살아있게 됩니다.

rvalue인 a + b는 해당 수식이 소멸되는 시점에 사라져야 하지만, rvalue reference로 참조하게 되면 lifetime이 연장되어 존재하게 됩니다.


이러한 value 유형을 xvalue ("eXpiring" value) 라고 합니다.


xvalue는 lvalue처럼 identity를 갖지만 추가로 movability를 갖습니다.

lifetime이 끝나도 identity가 유지되는 한 존재하게 됩니다.


(기존의) lvalue와 xvalue를 묶어서 glvalue("generalized" lvalue) 라고 부릅니다.

glvalue는 identity가 있다는 특징이 있습니다.


기존의 rvalue는 임시적이고 identity를 갖지 않지만, xvalue가 등작했기 때문에 xvalue까지를 포함하여 rvalue라고 합니다.

대신 xvalue가 아닌 rvalue들을 prvalue (pure rvalue) 라고 부릅니다.





rvalue reference의 진정한 가치를 알려면 move semantics에 대해 이해해야 합니다.

move semantics에 대해서는 다음 글에서 이야기하려고 합니다.




참조1 (The main fatures of CPL) : http://comjnl.oxfordjournals.org/content/6/2/134.full.pdf+html

참조 2 : http://blog.smartbear.com/development/c11-tutorial-explaining-the-ever-elusive-lvalues-and-rvalues/

참조 : http://scor7910.tistory.com/66

참조 : http://en.wikipedia.org/wiki/Rvalue_reference#rvalue_reference

참조 : http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

참조 : http://stackoverflow.com/questions/371503/why-is-i-considered-an-l-value-but-i-is-not

참조 : http://c0x.coding-guidelines.com/6.3.2.1.html

참조 : https://prog.woong.org/11

저작자 표시
신고

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

[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
[C++11] Variadic template  (0) 2013.11.06
[C++11] unique_ptr  (7) 2013.11.01
[C++11] Type Inference: auto  (4) 2013.11.01
Posted by 소혼
TAG C++11
목차로 가기


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



먼저 짧은 영어 탓에 variadic이라는 단어부터 찾아봤습니다.

하지만, variadic이란 단어는 원래 존재했던 단어는 아닌듯 합니다. (http://en.wiktionary.org/wiki/variadic)

어원은 variable 과 -adic 이 결합된 단어라고 하며, `임의의 많은 변수를 취하는` 이란 뜻입니다.


C언어를 접해서 쓰고 있는 사람이라면 printf를 생각하면 쉬울 듯 합니다.

printf는 대표적인  variadic function입니다.

### c++

// printf의 선언

int printf(const char *format, ...);


Variadic Template을 지원한다는 것은 결국 임의의 많은 template parameter를 취하는 템플릿을 지원한다는 것을 의미합니다.


기본적인 모양은 아래와 같습니다.

### c++

template<typename ... Values> class tuple;

(코딩 스타일은 어떻게 하는 것이 좋은지 모르겠네요. ... (ellipse operator) 과 typename, Values사이에는  space가 있어도 되고 없어도 되는듯 합니다.)


인스턴스를 만들때는 아래처럼 쓰게 됩니다.

### c++

// 세개의 template 인자를 갖는 some_instance_name

tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> some_instance_name;

//인자의 개수가 0개여도 괜찮습니다.

tuple<> a;


몇개의 인자를 제한하고자 하면 아래와 같이 해당하는 인자들뒤에 typename ... values 를 적으면 됩니다.

### c++

template<typename T, typename ... Values> class tuple;


간단한 예제를 만들어봤습니다.

### c++

#include <iostream>
using namespace std;

class dog {
public:
    void speak() const { cout << "bow wow" << endl; }
};
class cat {
public:
    void speak() const { cout << "meow" << endl; }
};

template <typename T>
void speak(const T& p)
{
    p.speak();
}

template <typename T, typename ... ARGS>
void speak(const T& p, ARGS ... args)
{  
    p.speak();
    speak(args...);
}

int main()
{
    dog a, b, c, d;
    cat e, f, g, h;
    speak(a, e, b, f, c, g, d, h);
    return 0;
}

좀 억지스러운 면이 있네요(굳이 이렇게 어렵게 짤 필요는 없어보입니다.).

적절한 사용법은 찾아야 될듯 합니다.(실제웹킷에서 쓰는 예를  아래에 첨부했습니다.)


어쨌든 30라인의 speak라는 함수는 dog객체와 cat객체를 임의의 개수만큼 받을 수 있도록 되어 있습니다.이를 위해 두가지 버전의 speak함수를 구현했습니다. (13-17라인, 19-24라인)

19-24라인의 speak는 variadic template으로 구현되어 있습니다. 이 버전의 speak를 보면, 첫번째 템플릿 인자는 T로 받아서(19라인) speak()를 호출합니다. (22라인), 그리고 나머지 인자들은 args... 이용해 speak를 다시 호출합니다. (23라인)

즉, 재귀적으로 variadic template 메소드를 호출하다가 마지막으로 인자가 한개만 남게 되면 13-17라인의 speak 함수를 통해 출력하게 됩니다. 이런 형태의 template을 recursive template이라고 합니다.


만약 13-17라인의 speak 함수가 없다면, 컴파일 타임에 아래와 같은 에러를 출력하게 됩니다.(gcc)

variadic_template.cpp: In instantiation of ‘void speak(const T&, ARGS ...) [with T = cat; ARGS = {}]’:
variadic_template.cpp:18:5:   recursively required from ‘void speak(const T&, ARGS ...) [with T = cat; ARGS = {dog, cat, dog, cat, dog, cat}]’
variadic_template.cpp:18:5:   required from ‘void speak(const T&, ARGS ...) [with T = dog; ARGS = {cat, dog, cat, dog, cat, dog, cat}]’
variadic_template.cpp:25:33:   required from here
variadic_template.cpp:18:5: error: no matching function for call to ‘speak()’
variadic_template.cpp:18:5: note: candidate is:
variadic_template.cpp:15:6: note: template<class T, class ... ARGS> void speak(const T&, ARGS ...)
variadic_template.cpp:15:6: note:   template argument deduction/substitution failed:
variadic_template.cpp:18:5: note:   candidate expects 2 arguments, 0 provided


유사한 예제로, Dog객체와 Cat 객체가 순서대로 있어야 하는 speak를 아래와 같이 만들수도 있습니다.

### c++

template <class Dog, class Cat>
void speak(const Dog& d, const Cat& c)
{
    d.speak();
}

template <class Dog, class Cat, class ... ARGS>
void speak(const Dog& d, const Cat& c, ARGS ... args)
{
    d.speak();
    speak(args...);
}

int main()
{
    dog a, b, c, d;
    cat e, f, g, h;
    speak(a, e, b, f, c, g, d, h);
    //speak(e, b, f, c, g, d, h); //Compile Error!
    return 0;
}

이렇게  일부 인자만을 지정하는 것을 partial specialization이라고 부르기도 합니다.



ellipse operator

보신 바와 같이, ellipse operator(...)는 크게 두가지 형태로 사용됩니다.

첫번째로, template parameter list나 speak()와 같이 template body의 인자 목록에서 사용될 경우 parameter pack을 선언한다고 합니다. (전자의 경우 template parameter pack, 후자의 경우 function parameter pack)

### c++

// template parameter pack
type ... Args
typename|class ... Args
template < parameter-list > ... Args

// function parameter pack
Args ... args

결국 parameter pack 을 가지는 template이 Variadic template이라고 할 수 있습니다.



두번째로, spack()의 body에서 사용된 것처럼 (args ... ) ellipse operator 가 템플릿 또는 함수 호출 인자의 오른쪽에 나오는 경우, parameter pack은 unpack한다 또는 확장(expansion)한다고 합니다.


위 예제에서는 간단한 형태의 parameter pack expansion 을 보여드렸습니다. (args ... )

하지만, expansion이 어디서 일어나느냐에 따라 다양한 형태로 이뤄지게 됩니다.


확장이 이뤄질 수 있는 곳들은 다음과 같습니다. (아래 참조에 있는 것들을 가져왔습니다.)

Function Argument list

### c++

f(&args...); // expands to f(&E1, &E2, &E3)
f(n, ++args...); // expands to f(n, ++E1, ++E2, ++E3);
f(++args..., n); // expands to f(++E1, ++E2, ++E3, n);
f(const_cast<const Args*>(&args)...);
// f(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&X#)
f(h(args...) + args...); // expands to
// f(h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)


Template Argument list

### c++

template<class A, class B, class...C> void func(A arg1, B arg2, C...arg3)
{
    container<A,B,C...> t1;  // expands to container<A,B,E1,E2,E3>
    container<C...,A,B> t2;  // expands to container<E1,E2,E3,A,B>
    container<A,C...,B> t3;  // expands to container<A,E1,E2,E3,B>
}


Template Parameter list

### c++

template<typename... T> struct value_holder
{
    template<T... Values> // expands to a non-type template parameter
    struct apply { };     // list, such as <int, char, int(&)[5]>
};


sizeof operator

### c++

template<class... Types>
struct count {
    static const std::size_t value = sizeof...(Types);
};

만약 count<int, char> 이면  value는 2가 될 것입니다.


Initializer list of array

### c++

template<typename... Ts> void func(Ts... args){
    const int size = sizeof...(args) + 2;
    int res[size] = {1,args...,2};
}


Member initializer list

### c++

template<class... Mixins>
class X : public Mixins... {
 public:
    X(const Mixins&... mixins) : Mixins(mixins)... { }
};


### c++

#include <iostream>
using namespace std;

struct a1{};
struct a2{};
struct a3{};
struct a4{};

template<class X> struct baseC{
    baseC(int a) {printf("baseC primary ctor: %d\n", a);}
};
template<> struct baseC<a1>{
    baseC(int a) {printf("baseC a1 ctor: %d\n", a);}
};
template<> struct baseC<a2>{
    baseC(int a) {printf("baseC a2 ctor: %d\n", a);}
};
template<> struct baseC<a3>{
    baseC(int a) {printf("baseC a3 ctor: %d\n", a);}
};
template<> struct baseC<a4>{
    baseC(int a) {printf("baseC a4 ctor: %d\n", a);}
};

template<class...A> struct container : public baseC<A>...{
    container(): baseC<A>(12)...{
        printf("container ctor\n");
    }
};

int main(void){
    container<a1,a2,a3,a4> test;
    return 0;
}


lamda captures

### c++

template<class ...Args>
void f(Args... args) {
    auto lm = [&, args...] { return g(args...); };
    lm();
}


Exception specification list

### c++

template<class...X> void func(int arg) throw(X...)
{
 // ... throw different Xs in different situations
}




아래 link는 webkit에서 아직 공식 지원되지 않는 make_unique를 내부적으로 만들어서 쓰기 위해 variadic template 버전과 variadic template이 지원되지 않는 버전을 같이 만든 패치입니다.

http://trac.webkit.org/changeset/156000


참조: http://en.wikipedia.org/wiki/Variadic_templates

참조2 : http://en.cppreference.com/w/cpp/language/parameter_pack

참조3 : http://pic.dhe.ibm.com/infocenter/lnxpcomp/v111v131/index.jsp?topic=%2Fcom.ibm.xlcpp111.linux.doc%2Flanguage_ref%2Fvariadic_templates.html

저작자 표시
신고

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

[C++11] Move semantics  (4) 2013.11.10
[c++11] rvalue reference  (1) 2013.11.07
[C++11] Variadic template  (0) 2013.11.06
[C++11] unique_ptr  (7) 2013.11.01
[C++11] Type Inference: auto  (4) 2013.11.01
c++11 스터디(목차)  (0) 2013.11.01
Posted by 소혼
TAG C++0x, C++11
목차로 가기


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


unique_ptr는 C++에서 제공하는 스마트 포인터입니다.

(TODO: 스마트 포인터에 대한 설명 추가)


unique_ptr를 사용하면 동적으로 힙 영역에 할당된 인스턴스에 대한 소유권을 얻고 unique_ptr 객체가 사라지면 해당 인스턴스를 해제하게 됩니다.

소유권을 갖기 때문에 인스턴스를 소유하는 unique_ptr은 동시에 두개가 되어선 안됩니다.

(둘이 된 경우 소멸되는 과정에서 double free 에러가 발생하게 될 것입니다.)


unique_ptr를 사용하려면 <memory> 헤더를 인클루드하면 됩니다.


간단한 unique_ptr의 사용 예제입니다.

### c++

#include <iostream>
#include <memory>

using namespace std;
void f()
{  
    unique_ptr<int> a(new int(3));
    cout << *a.get() << endl;
}

int main()
{  
    f();
}

a는 f()함수가 사라짐과 동시에 소멸됩니다. 사용자가 굳이 delete를 해줄 필요가 없고 unique_ptr<int> 객체인 a가 자신의 소멸 시점에  할당된 메모리를 제거할 것입니다.

예제에서는 unique_ptr의 메소드중 하나인 get()을 이용해 할당된 메모리를 얻어 출력하고 있습니다.


a를 선언하는 방법은 아래와 같이 할 수도 있습니다.

### c++

unique_ptr<int> a = unique_ptr<int>(new int(3));


아래와 같이 사용하는 것도 가능합니다.

### c++
unique_ptr<int> factory()
{  
    return unique_ptr<int>(new int(3));
}

void f()
{
    unique_ptr<int> a = factory();
    cout << *a.get() << endl;
}


하지만, 아래와 같이 대입을 하는 것은 불가능합니다.

### c++

unique_ptr<int> a = unique_ptr<int>(new int(3));
unique_ptr<int> b = a; // error!!


이 경우 아래와 같은 에러가 발생합니다. (gcc 기준)

$ g++ unique_ptr.cpp -std=c++11
unique_ptr.cpp: In function ‘void f()’:
unique_ptr.cpp:14:25: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>; std::unique_ptr<_Tp, _Dp> = std::unique_ptr<int>]’
In file included from /usr/include/c++/4.7/memory:86:0,
                 from unique_ptr.cpp:2:
/usr/include/c++/4.7/bits/unique_ptr.h:262:7: error: declared here


std::move

데이터를 이동시키고자 할때는 아래 예제처럼 std::move를 사용해야 합니다.

### c++

void f()
{
    unique_ptr<int> a(new int(3));
    unique_ptr<int> b = move(a);
    cout << *b.get() << endl;
    //cout << *a.get() << endl; //Segmentation Fault!
}

move를 호출하면 a가 소유하고 있는 객체(new int(3))는 b에게 넘어갑니다. 따라서 a는 empty 상태가 되고 이러한 a를 통한 접근은 segmentation fault를 야기하게 됩니다.


위에서 간단히 int를 할당하여 int의 raw pointer를 얻는 법을 계속 보여드렸습니다. 하지만 이런 접근은 그다지 안전하다고 볼 수 없습니다.

unique_ptr에 객체를 할당하고 객체의 메소드를 사용하는 것이 더 일반적인 사용법이라고 생각됩니다. 이 때는 기존에 직접 할당했을 때와 마찬가지로 ->를 사용하여 접근할 수 있습니다. 간단한 예제를 만들어보았습니다.

### c++

#include <iostream>
#include <memory>

using namespace std;
class house
{
public:
    house(int window, int door)
        : m_window(window)
        , m_door(door)
    { }
   
    int window() const { return m_window; }
    int door() const { return m_door; }

private:
    int m_window;
    int m_door;
};

int main()
{
    unique_ptr<house> home(new house(4, 1));
    cout << home->window() << " windows and " << home->door() << " doors" << endl;

    return 0;
}

home은 house의 객체가 아니라 unique_ptr<house>의 객체입니다. 하지만 window()나 door()와 같은 house의 메소드에 접근할 수 있습니다. (사실은 unique_ptr이 ->를 오버라이드하는 것으로 보는 것이 더 정확합니다.)


std::unqie_ptr::reset

만약 unique_ptr에 할당된 값을 지우거나 다른 값으로 바꾸고 싶다면 reset이란 메소드를 사용하면 됩니다.


위 예제에서 main부분만을 아래와 같이 변경해보겠습니다.

### c++

int main()                                                                         
{                                                                                  
    unique_ptr<house> home; //empty                                                
                                                                                   
    home.reset(new house(2, 1));                                                   
    home.reset(new house(4, 1));                                                   
    home.reset();
                                                                                   
    home.reset(); //nothing happend                                                
                                                                                   
    return 0;                                                                      
}

home 객체는 empty 로 생성되었습니다. 하지만 5번 reset을 통해 house(2, 1)의 ownership을 갖게 됩니다.

6번 reset을 수행하면 위에서 생성된 house(2,1)은 소멸되고 house(4, 1)의 ownership을 갖게 됩니다.

7번 라인과 같이 인자 없이 수행하면 갖고 있는 객체를 소멸시키게 됩니다.


이 동작은 9번 라인과 같이 현재 객체가 없는 경우에도 아무런 문제가 없습니다.


std::unique_ptr::release

현재 소유한 인스턴스의 소유권을 해제 없이 놓고자 할때는 release라는 메소드를 사용합니다.

이 경우, 반환된 인스턴스를 직접 해제해 주어야 합니다.


만약 현재 unique_ptr객체가 empty였다면, 반환된 인스턴스는 nullptr이 될 것입니다.

### c++

int main()
{
    unique_ptr<house> home; //empty

    house *p = home.release();
    if (p)
        cout << "It's not printed" << endl;
    home.reset(new house(4, 1));

    p = home.release();
    if (p) {
        cout << "p should be released" << endl;
        delete p;
    }

    return 0;
}


custom deleter

이미 알고 계시겠지만, unique_ptr은 메모리의 할당에는 관여하지 않으면서 메모리의 해제를 수행합니다, 따라서 만약 메모리를 new가 아니라 malloc과 같이 다른 형태로 할당했다면 문제가 발생할 것입니다. 이때는 custom deleter를 구현해주어야 합니다.


아래는 malloc으로 할당하고 custom deleter를 통해 해제하는 예입니다.

### c++

struct my_free
{
    void operator()(void* x) { free(x); }
};

int main()
{
    unique_ptr<int, my_free> a((int*)malloc(sizeof(int)));

    return 0;
}


추가정보1. WebKit에서는 OwnPtr이란 것을 사용했지만, c++11을 사용할 수 있게 된 이후, 현재 unique_ptr로 변경하는 추세입니다.

추가정보2 : c++14 에서는 unique_ptr의 factory인 make_unique가 도입될 듯 합니다.


참조 (custom deleter) : http://stackoverflow.com/questions/3477525/is-it-possible-to-use-a-c-smart-pointers-together-with-cs-malloc

참조 : http://en.wikipedia.org/wiki/Smart_pointer#C.2B.2B_smart_pointers


저작자 표시
신고

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

[c++11] rvalue reference  (1) 2013.11.07
[C++11] Variadic template  (0) 2013.11.06
[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
Posted by 소혼
TAG C++11

목차로 가기


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


- 업데이트
 * ts님이 지적해주신 제목 오타 수정

C/C++(C++11 이전의 C++)은 어떤 변수를 사용하려면 변수의 타입을 지정하여 선언(Declaration)을 해야만 합니다. 예를 들면 아래처럼 말입니다.

### c++

int a;

char b;


그러나, 템플릿과 STL등을 사용하다보면 어떤 타입을 지정하여 선언한다는 것이 간단한 일이 아닙니다.

예를 들어 아래처럼 복잡한 타입을 선언해야 할 수 있습니다. (내용은 타 코드에서 아무렇게나 가져왔습니다.)

### c++

HashMap<int, RefPtr<StaticPropertyAnalysis>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> map = getMap();


이를 위해 C++11에서 등장한 두가지 타입 추론(Type Inference) 방법중 하나가 바로 auto 입니다.

위 문장은 간단히  아래와 같이 선언할 수 있습니다.

### c++

auto map = getMap();

위 문장에서 map의 타입은 compile타임에 getMap의 반환값의 타입에 맞춰 변환될 것입니다.


사실 기존에 auto라는 키워드가 이미 존재했습니다. 스토리지 클래스(storage class)들 중 하나로 지역 변수(local variable)들의 기본 스토리지 클래스였습니다.


이 때 사용하던 auto의 용법은 아래와 같습니다.

### c

auto int i;


그러나 c++11을 사용하면 이 구문은 더이상 유효하지 않습니다.

다시말해, 위 예제를 그냥 c++11이전의 표준 컴파일러로 빌드하면 문제가 없지만 c++11 컴파일러로 빌드하면, 아래와 같은 에러가 발생합니다. (gcc 기준)

auto.cpp: In function ‘int main()’:
auto.cpp:5:14: error: two or more data types in declaration of ‘i’


기존의 auto는 머리속에서 지워버리고(최소한 c++에서는), 이제 c++11에서 다시 등장한 auto에 익숙해지기 위해 몇가지 예제를 보도록 하겠습니다.

### c++

auto i = 5; // i는 integer입니다.
auto str = "string"; // str은 string입니다.
auto* p = new Person; // p는 Person*입니다.
const auto* cp = p; // cp는 const Person*입니다.
auto& r = *p; // r는 Person&입니다.


위 코드를 디버거(gdb)로 실행해보면 아래와 같은 값들을 얻을 수 있습니다.

(gdb) p str
$7 = 0x40095c "str"
(gdb) p i
$8 = 5
(gdb) p p
$9 = (Person *) 0x602010
(gdb) p cp
$10 = (const Person *) 0x602010
(gdb) p r
$11 = (Person &) @0x602010: {name = 0x400960 "ryuan"}


auto의 위력은 STL을 이용해 반환값을 선언하거나, iterator와 같은 코드를 구현할 때 진가를 발휘합니다.

예를 들어, 아래는 vector를 탐색하는 흔한 for loop입니다.

### c++

for (std::vector<int>::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr)

이것을 auto를 이용하면 아래와 같습니다.

### c++

for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)



참조 1 : http://en.wikipedia.org/wiki/C%2B%2B11

참조 2 : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm

참조 3 (storage class) : http://msdn.microsoft.com/en-us/library/w9hwbe3d%28v=vs.80%29.ASPX

저작자 표시 비영리 변경 금지
신고

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

[C++11] Variadic template  (0) 2013.11.06
[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
Posted by 소혼
TAG C++11


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
이전버튼 1 2 3 이전버튼

티스토리 툴바