C++11

C++11은 C++의 최신버젼입니다.

gcc에서는 -std=c++0x 또는 -std=c++11을 붙여서 사용할 수 있습니다.

g++ -O2 -o Main -std=c++11 Main.cc

각 컴파일러가 C++11을 어디까지 지원하는지 알려면 아래 링크를 참고하세요.

STL 선언

더 이상 STL을 선언할 때, 공백을 추가하지 않아도 됩니다.

vector<pair<int,int> > a;
vector<pair<int,int>> a;

Initializer Lists

지금까지 vector, set과 같은 컨테이너에 초기값을 넣을 때, vectorpush_back, setinsert를 사용해야 했습니다.

이제 Initializer List {}를 이용해서 간단하게 선언할 수 있습니다.

vector<int> primes;
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
primes.push_back(7);
vector<int> primes = {2, 3, 5, 7};
vector<int> a = {1,2,3,4,5};
pair<string, int> p = {"Year", 2015};
map<string, int> age = { {"Sunyoung", 26}, {"Sangkeun", 26} };
vector<vector<int>> matrix = {{1, 2}, {3, 4}}; 
vector<pair<int,int>> l = {{1, 2}, {3, 4}, {5, 6}};
vector<pair<int,int>> a;

a.push_back(make_pair(1,2));
a.push_back({1,2});

구조체도 가능합니다!

struct Point {
    double x, y;
    Point(double x, double y) : x(x), y(y) {}
};
vector<Point> a;

a.push_back(Point(1,2));
a.push_back({1,2});

구조체의 경우에 다음과 같이 초기값을 넣을 수도 있습니다.

struct Point {
    double x = 1.0, y = 2.0;
};

tie

pair에 들어있는 값을 tie를 이용해 받아올 수 있습니다.

pair<int,int> p = {1, 2};
int a, b;
tie(b,a) = p;
cout << a << ' ' << b << '\n';

tie를 이용하면 swap도 간단하게 작성할 수 있습니다.

int a = 10, b = 20;
tie(a,b) = make_pair(b,a);

tie에서 무시하고 싶은 값이 있으면 ignore를 이용하면 됩니다.

int a = 10;
tie(a,ignore) = make_pair(20, 30);

min과 max

수 2개, 3개, 4개의 min을 구하는 경우 지금까지는 아래와 같이 작성했습니다.

min(1,2);
min(min(1,2),3);
min(min(1,2),min(3,4));

이제 Initializer List를 이용하면 됩니다!

min(1,2);
min({1, 2, 3});
min({1, 2, 3, 4});

당연히 max도 Initializer List를 지원합니다.

min과 max를 한 번에 구해야하는 경우에는 minmax를 사용할 수 있습니다. minmaxpair를 리턴하기 때문에, tie를 이용해 변수로 받아올 수 있습니다.

int t1, t2;
tie(t1,t2) = minmax({1,2,3});
cout << t1 << ' ' << t2 << '\n';

auto

auto를 이용해 변수 타입을 생략할 수 있습니다. Python과 같이 동적으로 변수의 타입이 결정되는 것이 아니고, 컴파일을 하면서 변수의 타입을 결정하는 것이기 때문에, auto a;와 같이 변수 타입을 결정할 수 없는 경우에는 사용할 수 없습니다.

auto a=0, b=1;

auto를 이용하면 iterator를 편리하게 사용할 수 있습니다.

vector<int> a = {1,2,3,4,5};
for (vector<int>::iterator it = a.begin(); it != a.end(); it++) {
    cout << *it << '\n';
}

위의 소스를 auto를 이용하면

vector<int> a = {1,2,3,4,5};
for (auto it = a.begin(); it != a.end(); it++) {
    cout << *it << '\n';
}

가 됩니다!

map<string,pair<int,int>> d = {{"Sunyoung", {1,2}}, {"Startlink",{3,4}}};
for (map<string,pair<int,int>>::iterator it = d.begin(); it != d.end(); it++) {
    cout << (it->first) << ' ' << (it->second.first) << ' ' << (it->second.second) << '\n';
}

이렇게 복잡한 for문도

map<string,pair<int,int>> d = {{"Sunyoung", {1,2}}, {"Startlink",{3,4}}};
for (auto it = d.begin(); it != d.end(); it++) {
    cout << (it->first) << ' ' << (it->second.first) << ' ' << (it->second.second) << '\n';
}

로 바꿀 수 있습니다.

Range-based for

vector<int> a = {1,2,3,4,5};
for (vector<int>::iterator it = a.begin(); it != a.end(); it++) {
    cout << *it << '\n';
}
for (int i=0; i<a.size(); i++) {
    cout << a[i] << '\n';
}
for (auto i : a) {
    printf("%d\n",i);
}

위의 for문 3개는 모두 같은 값을 출력하게 됩니다.

set<string> s = {"Choi", "Kim", "Park", "Lee"};
for (set<string>::iterator it = s.begin(); it != s.end(); it++) {
    const string &name = *it;
    cout << name << '\n';
}
for (const string &name : s) {
    cout << name << '\n';
}
for (auto &name: s) {
    cout << name << '\n';
}

위의 for문 3개도 모두 같은 값을 출력하게 됩니다.

Range-based for와 auto를 잘 활용하면 간결하게 코드를 작성할 수 있습니다. &를 사용하지 않으면 값복사가 일어나기 때문에 &를 사용하는 것이 좋습니다.

map<string, int> d = {{"brown",1}, {"red",2}, {"blue",6}};
for (auto &p : d) {
    auto &key = p.first;
    int val = p.second;
    cout << key << ' ' << val << '\n';
}

아래 예시를 살펴봅시다.

for (char c : "RGB") {
    // 4번
}
for (char c : string("RGB")) {
    // 3번
}

위의 for는 C언어 문자열을 사용하기 때문에, 마지막 NULL문자까지 c에 받아옵니다. 따라서, 총 4번 수행하게 되고, 아래는 C++ string 이기 때문에, NULL 문자가 없어 3번만 루프를 수행하게 됩니다.

for (auto i : {1,2,3,4}) {
    cout << i << '\n';
}

tuple

tuple은 사용하면 pair와 같지만, 더 많은 자료를 포함할 수 있습니다.

pair<int,pair<int,int>> p = make_pair(1,make_pair(2,3));
cout << p.first << ' ' << p.second.first << ' ' << p.second.second << '\n';

더 이상 위와 같이 작성할 필요가 없습니다.

tuple<int, int, int> t(1,2,3);
tuple<int, int, int> t2 = make_tuple(1,2,3);

tuple은 get을 이용해서 받아올 수 있습니다.

tuple<int, int, int> t(1,2,3);
int t1 = get<0>(t);
int t2 = get<1>(t);
int t3 = get<2>(t);
cout << t1 << ' ' << t2 << ' ' << t3 << '\n';

아래와 같은 방식으로는 사용할 수 없습니다.

tuple<int, int, int> t(1,2,3);
for (int i=0; i<3; i++) {
    int t = get<i>(t);
}

tupletie를 이용할 수 있습니다.

tuple<int, int, int> t(1,2,3);
int t1,t2,t3;
tie(t1,t2,t3) = t;

Lambda

Lambda는 익명 함수 이며, 다음과 같은 형식을 가지고 있습니다.

// [] : captures
// () : parameters
// {} : body
auto f = [](){};

sort 함수를 이용할 때, 지금까지 string을 역순으로 정렬하는 compare 함수는 다음과 같이 작성했습니다.

bool cmp(const string &u, const string &v) {
    return u > v;
}
int main() {
    vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
    sort(v.begin(),v.end(),cmp);
    for (auto &name : v) {
        cout << name << '\n';
    }
}

Lambda를 사용하면 다음과 같이 작성할 수 있습니다.

int main() {
    vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
    sort(v.begin(),v.end(),[](const string &u, const string &v) {
        return u > v;
    });
    for (auto &name : v) {
        cout << name << '\n';
    }
}

Lambda를 이용하는 경우에는 바깥에 있는 변수에 접근을 할 수가 없습니다.

다음과 같이 vp를 기준으로 정렬하는 경우에는 컴파일 에러를 받게 됩니다.

int main() {
    vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
    map<string,int> p = {{"Baekjoon", 5},{"Sunyoung", 4}, {"Choi",10}, {"Kim",1}};
    sort(v.begin(),v.end(),[](const string &u, const string &v) {
        return p[u] > p[v];
    });
    for (auto &name : v) {
        cout << name << '\n';
    }
}

[][&]로 변경해 바깥에 있는 변수에 접근할 수 있습니다.

 int main() {
    vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
    map<string,int> p = {{"Baekjoon", 5},{"Sunyoung", 4}, {"Choi",10}, {"Kim",1}};
    sort(v.begin(),v.end(),[&](const string &u, const string &v) {
        return p[u] > p[v];
    });
    for (auto &name : v) {
        cout << name << '\n';
    }
}

일반 함수와 같이 사용하려면 auto를 이용해 Lambda를 받아오고 호출해야 합니다.

int main() {
    auto sum = [](int a, int b) { return a+b; };
    printf("%d\n",sum(1,2));
}

위의 sum의 자료형은 function<int(int,int)> 입니다. function#include <functional>에 정의되어 있습니다.

#include <functional>
using namespace std;
int main() {
    function<int(int,int)> sum = [](int a, int b) { return a+b; };
    printf("%d\n",sum(1,2));
}

Lambda를 이용해 재귀 호출을 하려면, auto를 사용할 수 없습니다.

int main() {
    function<int(int)> f = [&](int x) {
        if (x <= 0) return 1;
        else return x * f(x-1);
    };
    printf("%d\n",f(10));
}

emplace

vector<pair<int,int>> a;
a.push_back(make_pair(1,2));
a.emplace_back(1,2);

queue<tuple<int,int,int>> q;
q.push(make_tuple(1,2,3));
q.emplace(3,4,5);

연습 문제 및 풀이

10869번 문제: 사칙연산를 Lambda와 Range-based for를 이용해 풀어볼 수 있습니다.

#include <functional>
#include <iostream>
#include <vector>
using namespace std;
int main() {
    int a,b;
    cin >> a >> b;

    vector<function<int(int,int)>> d;
    d.push_back([](int x, int y) {
        return x + y;
    });
    d.push_back([](int x, int y) {
        return x - y;
    });
    d.push_back([](int x, int y) {
        return x * y;
    });
    d.push_back([](int x, int y) {
        return x / y;
    });
    d.push_back([](int x, int y) {
        return x % y;
    });

    for (auto &f : d) {
        cout << f(a, b) << '\n';
    }

    return 0;
}

1076번 문제: 저항을 Initializer List를 이용해서 풀어볼 수 있습니다.

#include <iostream>
#include <string>
#include <map>
using namespace std;
int main() {
    map<string, int> d = {
        {"black", 0}, {"brown", 1}, {"red", 2},
        {"orange", 3}, {"yellow", 4}, {"green", 5},
        {"blue", 6}, {"violet", 7}, {"grey", 8},
        {"white", 9}
    };

    string a, b, c;
    cin >> a >> b >> c;

    long long ans = (long long)(d[a]*10 + d[b]);
    for (int k=0; k<d[c]; k++) {
        ans *= 10LL;
    }

    cout << ans << '\n';
    return 0;
}

10825번 문제: 국영수tuple과 Lambda를 이용해 간단하게 풀 수 있습니다.

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Person {
    string name;
    int kor, eng, math;
};
int main() {
    int n;
    cin >> n;

    vector<Person> a(n);
    for (int i=0; i<n; i++) {
        cin >> a[i].name >> a[i].kor >> a[i].eng >> a[i].math;
    }

    sort(a.begin(), a.end(), [](const Person &u, const Person &v) {
        return make_tuple(-u.kor, u.eng, -u.math, u.name) < make_tuple(-v.kor, v.eng, -v.math, v.name);
    });

    for (Person &p : a) {
        cout << p.name << '\n';
    }

    return 0;
}

국영수 문제는 아래와 같은 비교 함수로도 풀 수 있습니다.

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Person {
    string name;
    int kor, eng, math;
};
int main() {
    int n;
    cin >> n;

    vector<Person> a(n);
    for (int i=0; i<n; i++) {
        cin >> a[i].name >> a[i].kor >> a[i].eng >> a[i].math;
    }

    sort(a.begin(), a.end(), [](const Person &u, const Person &v) {
        if (u.kor > v.kor) {
            return true;
        } else if (u.kor == v.kor) {
            if (u.eng < v.eng) {
                return true;
            } else if (u.eng == v.eng) {
                if (u.math > v.math) {
                    return true;
                } else if (u.math == v.math) {
                    return u.name < v.name;
                }
            }
        }
        return false;
    });

    for (Person &p : a) {
        cout << p.name << '\n';
    }

    return 0;
}

댓글 (3개) 댓글 쓰기


sbjwin 8년 전

C++14도 부탁드립니다.


sgchoi5 6년 전

중간에 emplace_back 에 설명이 없어서 찾아봤는데, push_back 보다 쓰기 편하고, 성능이 더 좋다 입니다... 맞나요? : )

void push_back( T&& value );

template< class... Args > void emplace_back( Args&&... args );


sbjwin 6년 전

std::vector의 멤버 함수인 emplace_back은 C++11부터 추가된 멤버 함수로써 push_back과 같이 vector의 요소 끝에 원소를 추가하는 함수입니다. 두 함수의 가장 큰 차이점은, push_back과 같은 삽입 함수들은 삽입할 객체를 받지만 emplace_back과 같은 생성 삽입 함수는 삽입할 객체의 생성자를 위한 인자들을 받아 std::vector 내에서 직접 객체를 생성하여 삽입하므로 임시 객체의 생성과 파괴, 복사(혹은 move)를 하지 않아도 되어 성능상 더 유리하다는 것입니다. 부족하지만 참고되시길...