C++

C++ / 씨 플러스 플러스, 씨쁠쁠등으로 읽기도 한다.

C++C 언어에서 파생된 프로그래밍 언어 중 하나로, 비야네 스트롭스트룹(Bjarne Stroustrup)[1]이 만든 객체지향 언어이다. 초창기 코드 네임C with Classes[2]으로. 코드 네임에서 볼 수 있듯 C 언어객체지향 개념을 더하는 것이 시작이었다. 문법은 C 언어와 상당히 유사하지만 실질적으론 다른 언어로서 호환되지 않는다. 흔히 C++를 C언어의 슈퍼셋으로 생각하기 쉬우나, 이는 프로그래밍 패러다임적 측면에서 접근한다면 일리가 있는 이야기일지 몰라도 언어 자체는 개념적으로도 차이가 나는 부분이 있으므로 완벽한 의미에서의 호환이 된다고 볼 수는 없다. 게다가 C++ 98 버전 정도라면 몰라도, 특히 C++ 11 버전 이후로는 업데이트가 될수록 점점 문법이 C 언어와 달라지는 것을 보면.. 언젠간 C에서 원형을 따왔다는 것을 쉽게 못 알아볼지도. 당장 온라인 저지 등에서 C로 짜놓고 C++로 채점하면 실패 횟수가 하나 늘어날 것이다. 뼈아프다

특징[편집 | 원본 편집]

C의 저수준 접근을 그대로 허용하면서 객체지향 패러다임을 추가하였다. 덕분에 다른 객체지향 언어에 비해 복잡한 여러 가지 내용이 들어가게 되었다.

메소드의 정적바인딩[편집 | 원본 편집]

다른 객체지향 언어와 달리 C++은 속도를 위하여 기본적인 멤버함수는 정적바인딩을 사용하며, virtual 키워드를 사용했을 경우에만 동적바인딩을 하게 된다. 따라서 virtual 키워드를 사용하지 않는 경우에는 부모 클래스 포인터가 실제로 자식 클래스의 객체를 참조하고 있다고 하더라도 부모 클래스의 메소드가 호출됨에 유의해야 한다.

다중상속[편집 | 원본 편집]

클래스의 다중 상속이 허용된다. 매우 강력한 기능이지만 이것을 문제없이 잘 사용하려면 학습시간과 함께 프로그래머의 경험이 중요하다. 다중 상속이 문제가 되는 것은 다음과 같은 복잡한 상황을 야기하기 때문이다. 예를 들어 클래스 A와 B에 모두 foo()라는 메소드가 존재하고 클래스 C가 A와 B를 상속하는 경우, C에서 foo()를 호출할 때, 과연 어느 메소드를 호출해야 하겠는가? 다중 상속시에 이러한 부분을 제대로 컨트롤하지 않으면 심각한 문제를 야기할 수 있다. JavaC# 같이 나중에 등장한 객체지향 프로그래밍 언어에서는 다중상속이 아닌 단일 상속에 인터페이스를 사용하여 다중상속과 유사하게 사용할 수 있으면서 보다 쓰기 쉽게 만들었다.

컴파일 언어[편집 | 원본 편집]

C++ 는 스크립트 언어가 아닌 네이티브 언어이므로 컴파일러가 목적코드를 생성하여 응용 프로그램을 만든다. 대부분의 C++ 컴파일러는 C언어에 대한 컴파일도 지원하고 있다. 그러나 최근의 C++과 C언어는 각자의 길을 가게 되었는데, 이 때문에 C++ 컴파일러로 (최신의) C언어를 컴파일 하지 못할 수도 있다.

메모리[편집 | 원본 편집]

메모리의 동적 할당의 경우 자동으로 객체가 해제되지 않으며, 프로그래머가 직접 해제해야 한다. 동적 할당은 new 키워드로 하고 해제시에는 delete 키워드를 사용한다. 가비지 콜렉션 방식으로 묵시적 메모리 해제를 하는 Java와는 다르기 때문에 메모리 누수에 대한 고려가 필수적이다.

템플릿 메타 프로그래밍[편집 | 원본 편집]

템플릿 메타프로그래밍참조

버전[편집 | 원본 편집]

C++ 1.0[편집 | 원본 편집]

최초의 C++는 C의 전처리기로 구현되었다. 전처리기의 이름은 Cfront. C++ 초기 개발방향은 C와의 하위호환성을 보장하는 쪽이었다. 실제로 C++는 친숙한 C 언어와 비슷한 문법으로 많은 개발자들에게 어필할 수 있었다. 함수 및 연산자의 오버로딩이 overload라는 별도 키워드를 써야 사용이 가능했다. 동적 다형성이 가상함수를 통해 구현되어 객체지향의 모습을 얕게나마 보이기도 했다. C++ 1.0에 추가된 개념 중 일부는 C에 영향을 끼쳤는데, 현재 C/C++ 공통적으로 많이 접할 수 있는 const 키워드가 C++에서 C로 역이식된 개념 중 하나다.

C++ 2.0[편집 | 원본 편집]

다중 상속, 추상 클래스, 정적 멤버 함수, 멤버 포인터 연산자들이 추가되었고, 오버로딩이 불가능했던 연산자들의 오버로딩이 허용되는 등 많은 부분이 확장되었다. 비야네 스트롭스트룹이 C++ 2.0을 제약의 해제라고 소개할 정도. 기초적인 라이브러리들이 만들어지기 시작한 것도 이 시기이며, 전처리로 구현된 C++가 아닌 순수 C++ 컴파일러들 또한 만들어지기 시작했다.

C++ARM[편집 | 원본 편집]

C++ Annotated Reference Manual이 발표되면서 지금의 C++와 비슷한 모습을 갖추게 된 버전이다. 큰 변화로는 템플릿의 도입인데, 템플릿 메타프로그래밍이라는 새로운 흑마법패러다임을 열었다. 또한 표준 템플릿 라이브러리(STL)도 추가되어 지금까지 다양한 알고리즘과 기능들이 지원되고 있다.

C++98[편집 | 원본 편집]

어느 컴파일러를 사용하든 같은 결과를 보장하기 위해 만들어진 최초의 C++ 표준이다. C++98부터 namespace 개념이 추가되어 표준 라이브러리는 std 네임스페이스에 속하게 되었으며, 기존 라이브러리와 혼동을 피하기 위해 이때부터 표준 라이브러리의 헤더에서 .h가 빠지게 되었다.

C++03[편집 | 원본 편집]

C++98을 대체하는 표준이지만 이름만 바뀌었지 사실상 C++98와 다른 점은 없다![3] 하나 눈여겨볼 부분은 벡터의 메모리 연속성이 표준에 보장된 것.

C++TR1[편집 | 원본 편집]

C++ Technical Report 1이라는 이름의 문서에서 제안된 라이브러리의 통칭이다. 줄여서 TR1이라 쓰고 읽는다. 한글로는 C++ 기술 보고서 1이지만 이렇게 읽는 사람은 아무도 없다. C++03 규격에서 확장에 필요한 라이브러리들을 정리한 것인데, Boost에 들어가 있는 라이브러리들이 상당수 존재한다. 튜플이나 정규 표현식, 스마트 포인터, 배열 컨테이너 등의 라이브러리들이 추가되었으며, 기존 C++ 표준 라이브러리와 구분하기 위해 std::tr1이라는 namespace로 정의되어 있다. TR1에 도입된 라이브러리들은 그대로 C++11에 들어가게 된다.

C++11[편집 | 원본 편집]

2010년 이전에 나올 것으로 예상되어 초기 개발명이 C++0x이었지만 때를 한참 넘겨 2011년에 공개되었다. C++11에서는 다른 프로그래밍 언어에서 사용되던 편리한 문법과 개념이 많이 추가되었다

문법의 변화[편집 | 원본 편집]

C++11 최종 표준 사양 문서인 Programming Languages - C++ N3290 참고.

  • 유니코드에 대한 지원이 강화되었다.
UTF-8, UTF-16, UTF-32지원을 위한 자료형이 추가되었으며, 변환에 필요한 라이브러리가 추가되었다. 다만 비주얼스튜디오의 경우, 2015버전부터 지원한다.
char16_t a = u'리';  // ISO 10646 문자집합 중 단일 16비트 유닛을 취급. 최소 2바이트. 부호 없음.
char32_t b = U'브';  // ISO 10646 문자집합을 취급. 최소 4바이트. 부호 없음.
wchar_t c = L'레';  // 1바이트로 표현 못하는 문자 취급. 크기는 미정의.

auto ucs4_ga = '\uAC00';  // 16진수로 UCS-4 문자값 표기 (0x0000AC00) 한글 '가'.
auto ucs4_poo = '\U0001F4A9'  // 16진수로 UCS-4 문자값 표기 (0x0001F4A9) 똥 그림.


  • overide키워드가 추가되었다
overide 키워드는 자식 클래스가 부모 클래스의 멤버 함수를 재정의할 때, 재정의해야 할 부모클래스의 멤버함수가 없을 경우, 컴파일 단계에서 에러를 뿜어준다.
struct A
{
    virtual int func(char x);
};

struct B : A
{
    int func(int x) override;  // 오류! 이 함수는 가상함수를 오버라이드 하지 못했음.
    int func(char x) override; // ok
};


  • final 키워드가 추가되었다.
더 이상 상속을 못하게 하거나, 오버라이드를 금지하는 키워드이다. 아래는 상속 금지.
struct AAA final  // 상속 금지.
{ ...생략... };

struct BBB : AAA  // 오류!
{ ...생략... };
아래는 오버라이드 금지.
struct A
{
    virtual int func(char x) final;  // 오버라이드 금지.
};

struct B : A
{
    int func(int x);  // ok
    int func(char x); // 오류!
};


  • 기존의 auto 예약어의 기능이 없어지고 변수 선언시 초기화 값에 따라 변수형을 추론할 수 있게 됐다.
auto var = 1;  //이 경우 var의 변수형은 int형이 된다.
auto var2 = new Person();  //이 경우 var2의 변수형은 (Person*)이 된다.


  • 정적 배열의 경우 for문에서 자바의 for문과 같은 범위기반 for문(range-based for loop)을 사용할 수 있다.
사용자 컨테이너의 경우 차례대로 순환할 수 있는 iterator 인터페이스를 컴파일러에게 제공할 수 있다면 마찬가지로 이 새로운 for문을 사용할 수 있다. 표준 라이브러리에서 제공하는 컨테이너들은(vector, list 등) 대부분 그런 인터페이스가 이미 있기 때문에 그냥 사용하면 된다.
int a[] = {1,2,3,4,5};
for(auto & it : a)
{
    std::cout<<it<<endl;
}


  • 표현식(expression)의 타입추론을 돕는 decltype 키워드가 추가되었다.
decltype(1/1.0) a;  // double a;
decltype(a) b;  // double b;
decltype(main()) c;  // int c;
decltype(&c) d;  // int* d;
decltype((c)) e = c;  // int& e = c;
decltype(std::move(c)) f = 22;  // int&& f = 22;
이 키워드는 템플릿 메타 프로그래밍에서 요긴하게 쓰인다.
template <typename T, typename F>
auto execute(const T& value, F func) -> decltype(func(value))
{
    return func(value);
}


  • 공통 초기법(uniform initialization)이 도입되면서 초기화 방법이 통합되었다.
struct data
{
    int A, B;
    char C;
}

data x {1, 3, 'F'};

data func()
{
    return {2, 5, 'Z'};
}


  • 개체나 함수, 표현식을 컴파일 시점에 계산하도록 만드는 constexpr 키워드가 추가되었다.
constexpr int square( int x ) { return x * x; }

const int a{ square(22) };  // ok
int b{ square(a) };  // ok, 그러나 실행시점 계산.

int c{ square(b) };  // 오류! b는 상수식이 아니라서 square의 x를 알아낼 수 없음.
constexpr 함수는 재귀도 가능하다.
constexpr double factorial( double x )
{
    return x == 0.0 ? 1.0 : x * factorial( x - 1.0 );
}
// constexpr 함수의 재귀 깊이는 최소 약 512 중첩까지다.
클래스의 생성자를 constexpr로 만들 수 있다. 단, 이렇게 되면 그 클래스는 컴파일 시점에 계산할 수 있어야 한다.
class AAA
{
public:
    int x;
    constexpr AAA( int i ) : x{i} {}
    AAA() : x{22} {}
};

const int a{ AAA{22}.x };  // constexpr
const int b{ AAA{}.x };    // non-constexpr
const와 constexpr은 같은 개념이 절대 아니다. const는 이것은 읽기 전용이다.를 의미하고 constexpr은 이것은 컴파일 시점에 계산된다.를 의미한다. 아래는 const와 constexpr의 차이를 코드로 나타낸 것이다.
int func( int x )
{
    const int a{x};
    ...
}

int func( int x )
{
    constexpr int a{x};  // 오류!
    ...
}


  • Parameter Pack이 추가되어 가변 인자 템플릿을 구현할 수 있게 되었다.
template<typename... Types> void f(Types... args);


  • 최적화된 예외처리 기능을 제공하는 noexcept 키워드가 추가되었다.
try 구간이 시작되면 예외 처리기 및 스택 되감기 코드가 삽입되며 이러한 것들은 굉장히 무거운 기능이다. 그러나 어떤 예외가 터질지, 그 예외가 바깥으로 삐져나올지 말지, 만약 바깥으로 삐져나오면 어느 단에서 처리될 것인지의 여부를 컴파일러가 예측할 방법이 없으므로 관련된 코드마다 컴파일러는 이런 무거운 기능을 죄다 삽입한다.
void func_except()
{
    try { throw 22; }
    catch( int ee ) { ee = 0xEE; }
}
// 비록 이 함수가 자체적으로 예외를 처리하더라도 컴파일러는 그걸 모른다.
// 그래서 이 함수를 사용하는 다른 함수들도 스택 되감기를 위한 코드를 가지게 된다.

void a() { func_except(); }  // 이놈 때문에...

void b() { a(); }  // 스택 되감기 준비.
void c() { b(); }  // 스택 되감기 준비.
void d() { c(); }  // 스택 되감기 준비.
...
void z() { y(); }  // 스택 되감기 준비.

int main() { z(); }
이러한 오버헤드를 줄이기 위해 컴파일러에게 예외 힌트를 제공하는 컴파일러 개발자를 토하게 만드는throw() 문법이 있었지만 C++11부터 deprecated가 됐다. 그 대안으로 추가된 것이 noexcept 키워드다. noexcept가 지정된 함수는 예외가 일어나지 않거나, 예외가 일어나더라도 그 함수 내부에서 해결됨을 보장한다는 뜻이다. 즉, 컴파일 중 noexcept 함수를 만난 컴파일러는 그 함수가 사용되는 모든 코드마다 스택 되감기를 삽입하는 짓을 하지 않는다. 위의 코드에서 a() 함수를 a() noexcept로 만들면 b(), c(), d(), ... z() 함수까지의 스택 되감기 코드가 사라진다.[4]


  • nullptr 키워드가 추가되어 0과 구분되는 NULL을 공식으로 지원하게 되었다.
int* a = NULL;  // ok
int b = NULL;  // ok

int* c = nullptr;  // ok
int d = nullptr;  // 오류!

void f(int);
void f(int*);

f(NULL);  // <- void f(int) 호출
f(nullptr);  // <- void f(int* x) 호출.


  • 사용자 정의 리터럴이 추가되었고, 그 operator를 정의할 수 있게 되었다.
using u64 = unsigned long long;
constexpr int operator "" _k ( u64 x )
{
    return int{ x * 1024 };
}

const auto sum = 32_k + 128_k ;
// const int sum = 32768 + 131072;


  • using 키워드에 type alias 기능이 추가되었다.
typedef unique_ptr<unordered_map<int, std::string>> uum; //typedef
using uum = unique_ptr<unordered_map<int, std::string>>; //using

typedef void(*Func)(int, const std::string&); // typedef
using Func = void(*)(int, const std::string&); // using


  • using 키워드를 사용하여 alias template을 정식으로 지원하게 되었다.
//typedef
template<typename T1, typename T2>
struct uptr
{
    typedef unique_ptr<unordered_map<T1, T2>> uum;
};

//using (alias template)

template<typename T1, typename T2>
using uum = unique_ptr<unordered_map<T1, T2>>;


  • 우측값과 이동 생성자, 이동 대입 연산자가 추가되었다.
auto_ptr의 논리적 결함을 해결하기 위해 추가된 개념이다. 이 개념 덕분에 자료를 복사해야 하는지 옮겨야 하는지 예측이 가능하게 되어 여러 방면에서 극적인 성능 향상을 꾀할 수 있게 됐다.하지만 C++ 초보자들은 그저 멘붕멘붕.


  • 람다식및 익명함수가 추가되었다.
auto f = [](int x, int y) { return x + y; };
auto result = f( 1, 2 );  // result = 3;

[](){}();  // void 무명() { return; }을 호출한 것.


  • POD[5]의 정의가 수정되었다.
struct A {};                          // POD
struct B { B(){} };                   // standard-layout
struct C { virtual ~C(){} };          // 그 무엇도 아님.
struct D { int x; private: int y; };  // trivial
struct E { int x; int y; };           // POD
struct F { void foo(){} };            // POD (C++11 이전에는 성립 안됨.)


  • std::initializer_list가 추가되어 POD가 아니어도 리스트 형식으로 초기화가 가능해졌다.
  • extern 템플릿을 사용하여 템플릿 컴파일 시간을 크게 줄일 수 있게 됐다.
  • 대리 생성자(delegating constructor)가 추가됐다.
class Rect
{
public:
    Rect() : Rect(22) {}
    Rect(int d) : Rect(0, 0, d) {}
    Rect(int x, int y) : Rect(x, y, 22) {}
    Rect(int x, int y, int d) : Rect(x, y, x+d, y+d) {}
    Rect(int x, int y, int w, int h) : top(x), left(y), right(w), bottom(h) {}
    ...
};


  • delete 함수와 default 함수가 추가됐다.
class NonCopyable
{
public:
    int a;
    NonCopyable() {}
    NonCopyable( int x ) : a(x) {}
    NonCopyable& operator= ( const NonCopyable& src ) = delete;
};

NonCopyable A(22), B;

B = A;    // 오류! 복사 대입 연산자는 사용 금지된 함수입니다!
default 함수는 기본 생성자, 복사 생성자, 복사 대입 연산자, 이동 생성자, 이동 대입 연산자, 파괴자에게만 지정할 수 있다. 그냥 말 그대로 내용 없는 기본 함수를 컴파일러가 만들어준다.
class NonDefaultCtor
{
public:
    int a;
    NonDefaultCtor( int x ) : a(x) {}
};

NonDefaultCtor A1( 4 );  // ok
NonDefaultCtor A2;       // 오류! 기본 생성자가 없음.

class DefaultCtor
{
public:
    int b;
    DefaultCtor() = default;
    DefaultCtor( int x ) : b(x) {}
};

DefaultCtor B1( 4 );  // ok
DefaultCtor B2;       // ok


  • 새로운 함수의 표현식이 추가됐다.
auto NewStyle( int x ) -> int;
// int NewStyle( int x );


  • namespace의 버전 관리(versioning)를 쉽게 해주는 기능이 추가됐다.
namespace Julia
{
    inline namespace V20
    {
        int Age(void) { return 20; }
    }
    namespace V15
    {
        int Age(void) { return 15; }
    }
}

int a = Julia::V20::Age();  // a는 20
int b = Julia::V15::Age();  // b는 15

int c = Julia::Age();       // c는 20


  • 강타입 열거형(strong typed enums)이 추가됐다.
// 아래는 강타입 열거형
enum class Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
// 아래는 전통 열거형
enum Colors { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET };

Colors c = RED;         // ok
Weekday w = Sunday;  // 오류! Weekday::Sunday 로 해야됨.

int a = INDIGO;             // ok
int b = Weekday::Saturday;  // 오류! 열거형은 int형이 아닙니다.

// 아래는 Weekday가 사용하는 기호 상수와 중복되는 이름이 있음. 그래도 ok.
// 사용할 때 TimeTable::Monday 처럼 사용하면 됨.
enum class TimeTable { Monday, Tuesday, Wednesday, Thursday, Friday };

// 아래는 Colors가 사용하는 기호 상수와 중복되므로 오류!
enum TrafficLight { RED, GREEN };


  • 정적 assertion이 추가됐다. 컴파일 타임에 assertion을 발동시킨다.
// 예시 1:
static_assert( sizeof(void*) == 8, "The target machine needs LP64 or LLP64." );

// 예시 2:
template< class T, size_t N >
class SomethingAwesomeClass
{
    static_assert( N > 0, "N must be greater than zero." );
    ...
};

SomethingAwesomeClass<int,22> A;  // ok
SomethingAwesomeClass<int,0>  B;  // 컴파일 중단됨!

표준 라이브러리의 변화[편집 | 원본 편집]

  • std::thread가 추가되었고 멀티 스레딩을 지원하는 메모리 모델로 수정되었다. 또한 동기화 지원을 위한 std::mutex가 추가되었다.
  • 레퍼런스 카운터를 이용한 메모리 클래스인 std::shared_ptr와 std::weak_ptr, 그리고 독점소유 클래스인 std::unique_ptr이 추가되었다. 또한 std::auto_ptr은 비추천으로 바뀌었다.
  • 기존의 함수포인터를 대체하는 std::function 클래스가 추가되었다. 이번에 추가된 람다식이 이 클래스와 궁합이 잘 맞는다.
  • 시간에 관한 클래스 라이브러리 std::chrono가 추가되었다. 무단 변경 가능성 있는 실제 시간(wall time)을 다룰 때는 std::chrono::system_clock 클래스를, 변경되지 않고 꾸준히 흐르는 시간(monotonic)을 다룰 때는 std::chrono::steady_clock 클래스를, 가장 정밀한 틱 간격을 얻으려면 std::chrono::high_resolution_clock[6]을 사용하면 된다.
  • 난수에 관한 클래스 라이브러리 <random>이 추가되었다.하지만 쓰다보면 짜증나서 걍 rand 돌린다...[7] 크게 엔진과 어댑터로 구성된 발생기(generator)와 그것을 쪼개는 분배기(distribution)로 나뉘어 있다. 난수 전문가가 아니면 도저히 알아먹기 힘든 다양한 발생기와 균등 분포, 베르누이 분포, 푸아송 분포, 정규 분포, 표본 분포로 구분짓는 20여개의 분배기를 제공한다. 난수 하나를 얻기 위해서 엔진을 결정하고 시드를 결정하고 분배기를 결정한 다음, 분배기에 엔진을 물리고, 분배기를 돌려야 한다. 난수 전문가가 아니라면 일반적인 여건에서 정수형 균등 분배기에 메르센 트위스터 엔진을 연결하면 무난하다.
  • 정적 배열 클래스 std::array가 추가됐다. 말 그대로 선언하는 즉시 굳어버리는 고정 배열이며, C++에서 언어적으로 지원해주는 배열을 포장한 것이다.[8] 초기화 할 때 주어지는 요소들을 통해 배열 크기를 컴파일러가 알아서 잡아주지 못한다는 존나 심각한단점이 있다.
  • <algorithm> 라이브러리가 대폭 강화됐다. std::all_of, std::any_of, std::none_of 등등 자주 쓰일 법한 많은 것들이 추가됐다.
  • 간편하게 사용하는 이종간 데이터들의 묶음인 std::tuple이 추가됐다.[9]
  • 템플릿 변태질의 정점에 다다를 수 있는 <type_traits> 연장이 추가됐다. 진정 템플릿 덕후라면 이 라이브러리를 잘 활용하자. 실제로는 데이터 타입을 이래저래 조작하거나 식별할 수 있는 도구다. 모든 건 컴파일 타임에 이루어진다.
  • 비정렬 컨테이너인 std::unordered_map과 std::unordered_set이 추가됐다. 정렬하지 않기 때문에 당연히 기존의 std::map과 std::set보다 빠르다.타이핑이 귀찮은게 심각한 단점.
  • 단방향 리스트인 std::forward_list가 추가됐다. 얘는 그냥 앞만 보고 달리는 리스트다. 자기가 데이터를 몇 개 달고 있는지 모르니까 사용시 주의.
  • 정규 표현식을 다루는 std::regex가 추가됐다. 일부 C++ 개발자들에게는 혁명이라고 표현되는 개선점 중 하나.
그 외[편집 | 원본 편집]
  • 가비지 컬렉션에 대한 내용이 표준에 추가되었다, 하지만 어떠한 컴파일러도 구현하지 않았다.
  • 원래 C++11에 템플릿의 새로운 개념인 템플릿 변태질의 끝판왕인컨셉(Concepts)이 들어갈 예정이었다. 그러나 시간이 촉박하여 해당 개념의 추가는 차후로 밀려나고 말았다.

C++14[편집 | 원본 편집]

C++14는 C++11의 마이너 업그레이드이다.

  • 함수 리턴형 추론을 좀 더 강화했다.
// 예시 1:
auto Adder(int x, int y)
{
    return x + y;
}

// 예시 2:
decltype(auto) Wrapper() { return Kernel(); }
두 번째의 경우는 래핑 함수나 템플릿에서 요긴하게 활용 가능.
  • 2진수 리터럴을 표현할 수 있게 됐다.
auto bin = 0b101010;
  • 숫자 구분자가 추가됐다. 이제 좀 더 숫자를 읽기 편해졌다.
auto i = 100'000'000;
  • 제네릭 람다식이 가능해졌다.
auto adder = [](const auto a, const auto b) { return a+b; };
  • 람다식의 캡쳐에 자유롭게 표현식을 넣을 수 있게 됐다.
auto p = std::make_unique<...>(...);
auto result = [a = dice(mt), b = std::move(p)]{ return a + (*b); }();
  • constexpr 변수 템플릿이 가능해졌다.
  • constexpr 함수 내부에 if, switch, for, while이 가능해졌다.

C++17[편집 | 원본 편집]

C++17 언어에는 다음의 주요 기능이 추가되었다.

  • if문과 switch문에서의 초기화 구문 허용
  • 아스키코드 이외의 문자를 사용한 UTF-8 문자열 선언 허용[10]


C++17 표준 라이브러리에는 다음의 주요 기능이 추가되었다.

  • 파일 시스템
  • 병렬 프로그래밍[11]
  • 선택적인 개체 반환
  • 타입 세이프 공용체


C++20[편집 | 원본 편집]

C++20에는 다음의 주요 기능이 추가되었다.

  • Coroutine
  • 소스 코드 모듈화 지원[12]
  • 템플릿 매개변수에 명시적 조건을 추가할 수 있는 컨셉트 지원[13]

C++11에서 추가된 GC 관련 표준이 삭제되었다.

시범 사양[편집 | 원본 편집]

C++ 표준 워원회가 작성한 시범 사양으로는 네트워크 라이브러리, 리플렉션 그리고 2D GUI 라이브러리 등이 있다. 이러한 것들이 표준이 된다면, C++ 표준 라이브러리 만으로 크로스 플랫폼 소프트웨어를 만드는 일도 어렵지 않게 될 것이다.

참고 자료[편집 | 원본 편집]

각주

  1. 그의 홈페이지에는 자신의 이름을 어떻게 읽는지 본인이 직접 발음한 음성 파일을 제공한다. wav file이라는 부분.여기 FAQ 계속 읽다보면 숙제 도와달라는 요청에 시달린다는 글이 있다. 학교에서 C++ 숙제 받으면 창시자에게 달려가는 미국 학생들의 위엄.
  2. 위키백과나 다른 곳에서는 C++의 원래 명칭을 C with Classes라고 소개하고 있지만, 비야네 스트롭스트룹은 C with Classes를 발표한 적이 없다. C with Classes는 C++의 개발 코드 네임인 셈. 예를 들면 윈도우 XP의 코드 네임은 Windows Whistler이지만 내부에서만 쓰는 이름이었고 공식적으로 발표된 적은 없다. 즉, 발표한 적이 없는 C with Classes를 C++의 원래 이름이라고 말하는 것은 잘못된 것.
  3. 비야네 스트롭스트룹은 FAQ 페이지에서 C++03은 C++98의 버그 수정 릴리즈라고 밝혔다. 프로그래머는 따로 신경 쓸 부분이 없다고.
  4. 참고로, 이렇게 사용자를 믿은오빠를 믿은 컴파일러를 배신하고 noexcept 함수 바깥으로 예외를 던져버리면, 윗단에 그 예외를 받을 수 있는 코드가 있더라도 다 쌩까고 std::terminate()를 호출하여 프로그램을 그 자리에서 박살낸다...
  5. plain old data, memset이나 memcpy등을 사용할 수 있는 객체
  6. 플랫폼에 따라서는 system_clock이나 steady_clock이 high_resolution_clock 역할을 대신 하는 경우도 있다. 윈도우즈 환경에서는 high_resolution_clock을 steady_clock이 대신 하고 있다.
  7. 각각 독립적인 주사위를 굴려야 하는 상황이라면 당연히 rand 사용은 지양해야 할 것이다.
  8. iterator를 지원하고 배열을 다룰 때 발생하는 몇몇 실수를 사전 예방 해준다는 차이점이 있다.
  9. 비주얼스튜디오 2010의 경우 가변인자 템플릿 기능이 구현되지 않아서 라이브러리 개발자STL씨일듯?가 직접 재귀 템플릿 꼼수를 사용하여 std::tuple을 구현했다. 그래서 한 번에 받을 수 있는 데이터 종류의 수가 정해져 있다. 그 이후의 비주얼스튜디오는 어떻게 됐는지 다른 위키러가 추가바람.
  10. UTF-8 문자열 선언 자체는 이미 C++11에서 추가되었다.
  11. 정렬과 같은 표준 라이브러리의 함수에 이러한 기능이 추가되었다.
  12. 각각의 소스코드에 헤더 파일을 일일이 포함하는 대신, 미리 컴파일된 헤더 파일을 사용하는 것과 같다. 이는 컴파일 시간 단축에 효과적이지만, 매크로의 사용에 제약이 있기 때문에, C++로 작성된 소프트웨어의 소스코드의 구조가 급격하게 변화할 수 있다.
  13. 템플릿 변수의 조건을 일부러 틀리게 하는 트릭을 넣을 필요가 적어지기 때문에, 코드가 간결해지고 가독성이 증가한다.