반응형

C++11 :  범위기반 for 문

배경

 이미 C++11에서부터 존재했지만, 신경을 안쓰면 잘 모르는 for문의 기능이다. 이미 다른 언어들은 기존부터 foreach라는 키워드로 제공했던 기능이다.


 for문에서 직접 범위기반으로 반복하는 것이 가능 해짐으로써 STL 컨터이너 사용에 좀 더 편리 해졌다.



사용방법

#include <iostream>
#include <vector>

int main(const int argc, const char * argv[])
{
    std::vector<int> vec{ 1, 2, 3, 4};
    // 기존 반복자 사용방법
    auto itVec = vec.begin();
    for(; itVec != vec.end(); ++itVec)
    {
        std::cout << (*itVec) << std::endl;
    }

    // 범위 for문
    for(auto valVec : vec)
    {
        std::cout << valVec << std::endl;
    }
    return 0;
}


 첫 for문은 반복자를 이용한 원소 출력인 반면, 두번째 for문은 범위를 이용해서 원소를 확인하는 방법이다. auto 키워드는 C++11에서 가장 먼저 사용하게 되기때문에 자세한 설명은 생략한다.(auto 링크)



주요 특징

 1. 기존 반복자를 사용하지 않고 시퀀스(메모리가 연결된 자료형)형 컨테이너의 원소를 확인을 할 수 있다.
 2. 읽는 원소는 시퀀스 내부 원소의 형으로 변환된다.

 3. 범위 for문을 사용하여 읽는 시퀀스내부의 원소 값을 수정할 수 없다.



참조자료

MSDN 범위기반 for문




반응형
반응형

C++11 : STL std::array 정적배열

배경

 C++11에서 등장한 array는 기존의 정적 배열(이제는 C Style array 라고 불림)을 개선하기 위해서 등장을 했다. C/C++ 외의 다른 프로그래밍 언어를 조금 훝어보면 알 수 있다.


 JAVA, JS, C# 등에서의 배열을 선언/정의 할때 부가 정보(Length 등)가 같이 있는 것에 비해서 C++11이전의 C Style static array은 단순히 연속된 메모리 공간의 앞부분을 가르키는 포인터에 불과 했었다. 이로 포인터를 사용할 경우 잘못된 메모리 참조 또는 이를 개선하기 위한 추가 코딩으로 인한 생산성 저하로 이어지는 문제가 있다.


 그래서 C++11이전에서는 std::vector를 사용하기도 했다. 그러나 C Style Array에 비해서 성능 저하의 부담이 크며, 오버플로워가 일어나면, 동적으로 용량을 늘려 버리는 바람에 정해진 크기를 버퍼로 사용하기에는 잠재적인 문제가 있을 수 있다(물론 좋은 프로그래머는 이런 문제를 예방을 할 것이다).


 std::array는 vector보다 경량이며, 기존의 정적 배열의 성질을 가졌으며, 반복자등 일부 STL 컨테이너를 사용할 수 있게 만들어졌다.



선언 및 초기화 방법

 array표준헤더파일을 포함해야 사용할 수 있다. 타입과 배열크기를 입력하고 기존 컨테이너처럼 선언하고 사용할 수 있다. <>에 첫인자는 자료형(type), 두번째 인자는 크기를 입력해야 한다.

#include <array>

int main(const int argc, const char * argv[])
{
    std::array<int, 5> arr1 = {1, 2, 3};
    std::array<int, 5> arr2(1, 2, 3);
    std::array<int, 5> arr3{1, 2, 3};

    return 0;
}


주요 특징

 정의된 array의 남는 원소에는 0으로 초기화가 된다.

 array도 vector와 같이 객체명(혹은 변수명) 뒤에 대괄호로 배열처럼 사용할 수 있다.

 vector처럼 반복자를 사용할 수 있다.


예시

// arrayEx.cpp
#include <array>
#include <iostream>

int main(cosnt int argc, const char * argv[])
{
    std::array<int, 5> arr1{1, 2, 3};
    // 네번째 int에 접근하여 값을 대입함
    arr1[3] = 4;
    // 반복자처럼 사용 가능
    auto itArr = arr1.begin();
    for(; itArr != arr1.end(); ++itArr)
    {
        std::cout << (*itArr) << std::endl;
    }
    // 출력결과 arr1[4](5번째)는 0으로 초기화 되어 있음
    return 0;
}


 size() 함수로 배열의 크기를 알 수 있다. 단, capacity()가 없다. 이는 vector와 가장 큰 차이 중 하나다. 이는 array경우 size()와 capacity()가 따로 있을 필요가 없기 때문이다.

 array로 선언된 객체명은 array라는 컨테이너의 포인터이기이다. 이 때문에 기존의 정적 배열의 첫번째 포인터가 필요할 경우 vector와 같이 data()를 호출해서 사용해야 한다. 이는 오래된 라이브러리를 호환해야 한다던가 버퍼로 사용하기에 적절하다.

 fill()로 특정 원소값으로 모든 원소를 초기화 할 수 있다.


이 밖의 자세한 특징은 cpprefernce 문서를 참조하면 된다.



참조자료

cppReference 문서




반응형
반응형

C++11 : 연역적 선언 auto (입문)

알게된 배경

 혼자 프로젝트를 진행을 하다 보니 가능하면 최신(2017년에 2011년에 재정된 표준을 사용하는 것이 과연 최신 일까?) 표준을 사용하기 위해서 공부하면서 알게 된 것들이다. 최신 기술이 항상 좋은 건 아니지만, 새로운 기술은 항상 이전 기술을 사용하면서 축적된 경험으로 부터 개선점이 나오기 때문에 반대로 나쁘다고만 할 수 도 없고 생각든다.

 해당 내용은 effective modern c++를 많이 참조했다.


auto 키워드

 C++98 에서도 존재하던 키워드였지만, C++11에서 급진적으로 바뀐 키워드중 하나다. 즉, C++98에도 역할이 다른 키워드이니 C++11을 경계로 이전 버전에서는 호환이 안된다. 다만, 다행스러운건 이전 버전에서는 거의 사용이 안되던 키워드였기 때문에 웬만하면 큰 문제가 발생되지 않는다.


 적절한 한글 명칭으로는 '연역적 형식선언' 정도 붙일 수 있다. auto 키워드는 JS와 C#에 존재하는 var와 유사한 역할을 한다. 즉, 객체 혹은 변수를 선언할때 초기화 하는 값에 의해서 형이 정해지는 것이다.

예시)

int a1 = 10;
auto a2 = 10;    // a1 == a2

int b1;
b1 = 10;
auto b2;    // error
b2 = 10;




 초기화 하는 형이 있어야 형을 선언할 수 있기 때문에 반드시 초기화를 해야 하며, auto 키워드는 변수형 뿐만 아니라 객체로도 사용되기 때문에 STL의 iterator를 선언할 경우 상당히 많은 코드를 줄일 수 있다.

예시)

std::vector<int> arrVec = {1, 2, 3, 4, 5};
std::vector<int>::iterator it1 = arrVec.begin();
auto it2 = arrVec.begin();
// it1[1] == it2[1]




장점

 auto 를 사용함으로써 얻는 장점은 3가지로 자주 언급이 된다.

1. 코드의 길이가 줄어듬

2. 초기화 강제화로 실수가 줄어듬

3. 코드의 유지보수(리펙토링)가 쉬워짐

4. 형 선언 실수를 방지할 수 있음


사실 STL의 자료형을 많이 사용해본 입장에서는 1, 2번의 장점이 매우 크게 느껴진다.


단점

1. 대리자(proxy) 형식 때문에 형식을 잘못 연역하는 경우가 있음

2. 코드만 봤을때 직관적이지 않음(이는 IDE의 부가 기능으로 어느정도 해결 할 수 있음)


 1번의 경우 대표적인 예로 vector<bool> 형이 많이 거론된다. bool 값은 추상적으로 1비트로 표시할 수 있기 때문에 vector 템플릿은 bool 형을 받으면 비트형으로 저장을 하게 된다. 즉, vector<bool> bVec(5)를 선언하면, bVec는 1바이트의 5비트를 갖고 있는 것이다. 문제는 C++은 바이트 단위로 처리를 하기 때문에 bool형은 실제로 바이트로 되어 있는데, 이러한 자료형의 이질성을 해소하기 위해 중간에 대리자라는 형식이 존재한다.


 문제는 이렇게 중간에 껴있는 대리자를 통하여 포인터를 넘겨 받을 경우 대리자가 어떻게 구현되었는지에 따라 영향을 받게 된다. 이러한 경우 경우에 따라 연역적 형 선언에 실패하게 된다. 따라서 이러한 경우 명시적으로 선언을 해줘야 한다.


결론

 이러한 auto 키워드 사용은 권장이지 의무는 아니다. 하지만, 장점과 단점을 생각해서 사용하는 것이 더욱 즐겁고 효율적인 코딩이 될 것이다.


참조자료

Effective Modern C++

반응형

+ Recent posts