[C++11] 유니폼 초기화(Uniform Initializer)

유니폼 초기화는 객체의 초기화를 보다 간단한 코드만으로 구현할 수 있는 기능입니다. 예를 들어 다음과 같은 Product라는 클래스가 있다고 할때 이 Product 클래스의 객체를 초기화하여 생성하는 경우를 예를 들어 보겠습니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

class Product
{
private:
    string name;
    int cost;
public:
    Product(const string& name, int cost) : name(name), cost(cost) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    Product r("Apple", 100);
	
    return 0;
}

이미 흔히 알고 있는 방식으로 18번 코드와 같이 객체를 초기화하면서 생성하고 있습니다. 이런 초기화 방식에 대해 C++11은 다음과 같은 방식도 지원합니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

class Product
{
private:
    string name;
    int cost;
public:
    Product(const string& name, int cost) : name(name), cost(cost) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    Product r {"Apple", 100};
	
    return 0;
}

변경된 부분은 15번 코드입니다. 바로 () 대신에 {}를 사용해 초기화를 하고 있습니다. 여기까지는 별 것 없는 것 같습니다만 이러한 초기화 방식이 유니폼 초기화(Uniform Initializer)입니다. 이 별것 없을 것 같은 초기화 방식이 배열이나 콜렉션(Collection, Container)에서는 다음처럼 응용되어 사용할 수 있습니다.

#include "stdafx.h"
#include 
#include 
#include 

using namespace std;

class Product
{
private:
    string name;
    int cost;
public:
    Product(const string& name, int cost) : name(name), cost(cost) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    vector v {
        {"Apple", 100},
        {"Orange", 200},
        {"Grape", 300}
    };

    return 0;
}

유니폼 초기화를 이용하여 vector 컨테이너에 3개의 객체를 생성하고 있습니다. 이러한 방식을 이용하지 않고 3개의 객체를 초기화하여 컨테이너에 추가하는 기존의 코드를 생각해 본다면 이러한 유니폼 초기화 방식이 얼마나 직관적인지 쉽게 짐작해 볼 수 있습니다.

[C++11] 범위 기반 for 문

for 문은 초기값과 반복조건 그리고 증감(감소)문으로 구성되어 있습니다. C++11에서는 다소 복잡한 for 문 대신 보다 간결한 범위 기반의 for 문을 지원합니다. 아래의 예를 살펴보도록 하겠습니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(int i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    for(vector::const_iterator it = v.cbegin(); it != v.cend(); ++it) {
        cout << *it << endl;
    }

    return 0;
}

15번 코드를 보면 for문에 대한 초기값, 조건값, 증감문으로 구성되어 있는 것을 볼 수 있습니다. 이를 범위 기반의 for 문을 사용하여 다음과 같이 단순하게 코드를 구성할 수 있습니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(int i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    for(int i: v) {
        cout << i << endl;
    }

    return 0;
}

변경된 15번째 줄 코드를 보면 오직 반복하여 얻는 값에 대한 정의만 있습니다. 매우 직관적이라는 것과 반복에 대한 범위를 고민할 필요가 없다는 것을 알 수 있습니다. 이 범위 기반의 for문에 대해 한가지 더 살펴본다면 바로 반복에 대한 참조값의 사용입니다. 위의 코드는 참조값이 아니므로 반복문 안에서 값에 대해 변경할 경우 원본은 변경되지 않는다는 것입니다. 원본의 변경이 필요할 경우 다음과 같이 참조값을 이용하여 for 문을 구성할 수 있습니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(int i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    for(int &i: v) {
         i*= 2;
    }

    for(int i: v) {
        cout << i << endl;
    }

    return 0;
}

15번 코드에서 int &i와 같은 참조 타입을 사용하였으므로 원본값을 변경할 수 있습니다. 위의 코드는 C++11에서 새롭게 정의되어 지원되는 auto 기능을 이용하여 다음처럼 동일한 기능으로 변경할 수 있습니다.

#include "stdafx.h"
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(auto i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    for(auto &i: v) {
        i *= 2;
    }

    for(auto i: v) {
        cout << i << endl;
    }
	
    return 0;
}

한번 정의된 데이터에 대해서 이후에 굳이 그 타입을 찾아 입력할 필요없이 auto 키워드를 통해 매우 직관적이고 꼭 필요한 사고(Thinking)만을 할 수 있도록 지원하고 있습니다.

[C++11] auto 키워드

원래 auto 키워드는 저장 클래스 지정자(storage class specifier) 중으로 하나로 기본 지정자입니다. 기본 지정라는 의미는 굳이 지정하지 않아도 자동으로 auto로 지정된다는 의미입니다. 그러다보니 거의 사용되지 않는 키워드였는데 C++11에서 이 키워드에 매우 강력한 기능을 부여하게 되었습니다.

C++11에서 auto에 대해 새롭게 부여한 기능으로써 의미는 컴파일 타임에서 자동으로 type을 지정할 수 있도록 하는 것입니다. 아래의 코드를 예로 살펴보면 직관적으로 auto의 의미를 파악할 수 있을 것입니다.

#include "stdafx.h"
#include ;
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(int i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    vector::iterator it = v.begin();
    while(it != v.end()) {
        cout << *it << endl;
        it++;
    }

    return 0;
}

위의 코드는 우리가 흔히 C++11 이전에 써오던 코드입니다. 눈여겨 봐야할 부분은 바로 15번 코드입니다. 반복자(iterator)의 타입을 선언하기 위해 vector::iterator과 같이 제법 긴 타입명을 사용하고 있습니다. 예제이니 그렇지 실제 코드에서는 더욱 더 긴 타입명이 빈번하게 나옵니다. 이를 auto라는 키워드를 통해 다음처럼 단순하게 만들 수 있습니다.

#include "stdafx.h"
#include ;
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v;
    for(int i=0; i<10; ++i)
    {
        v.push_back(i);
    }

    auto it = vInt.begin();
    while(it != v.end()) {
        cout << *it << endl;
        it++;
    }

    return 0;
}

변경된 부분은 오직 앞서 언급한 15번 코드입니다. 바로 vector::iterator 대신 auto를 사용했습니다. auto로 선언된 데이터 타입은 컴파일 시점에서 컴파일러에 의해 상당히 정확하게 그 타입을 유추해 결정해 줍니다.

[GIS] Point Counter – 폴리곤 안에 들어가는 포인트 수 세기

폴리곤 안에 들어가는 포인트의 수를 카운트해서 필드값으로 추가해 주는 툴입니다. 아래는 이 툴의 실행 화면입니다.

사용자 삽입 이미지

아래는 이 툴을 이용해 만들어진 SHP 파일을 가시화한 화면입니다. 헥사곤 안에 들어가는 건물의 수를 단계적 색상값으로 표현하고 있습니다.

사용자 삽입 이미지

이 프로그램은 아래의 링크를 통해 다운로드 받아 설치할 수 있습니다.

[GIS] PointToSomething, 포인트를 다양한 도형 폴리곤으로 변환하는 툴

포인트 SHP 파일을 정사각형, 삼각형, 육각형, 원 형태의 폴리곤으로 변환해 주는 툴입니다. 원본 포인트 SHP의 속성 정보도 함께 생성됩니다. 아래는 실행화면입니다.

설치 파일은 아래의 URL을 통해 다운로드 받을 수 있습니다. 이 프로그램의 소스 코드가 필요하신 분은 이메일을 통해 요청하시면 보내드리도록 하겠습니다.