반응형

반복자(iterator)

집합에서 요소 하나하나를 읽어오는 방법

  • begin : 집합의 첫 번째 요소의 주소 반환
  • end : 집합의 마지막 번째 다음 요소의 주소 반환
#include <list>


int main()
{
    int x[10] = { 1,2,3,4,5,6,7,8,9,10 }; // 배열 선언
    int* px = x; // 배열의 첫번째 요소를 가르키는 포인터 대입
    ++px; // 포인터 증가
    std::cout << *px << std::endl; // 다음 배열의 값 출력

    std::list<int> s = { 1,2,3,4,5,6,7,8,9,10 }; // 리스트 선언
    std::list<int>::iterator p = s.begin(); // 리스트의 첫번째 요소를 가르키는 iterator 대입
    // std::list<int>::iterator p; -> auto로 간소화 : auto p;
    ++p; // 이터레이터 증가
    std::cout << *p << std::endl; // 다음 리스트의 값 출력
}

기능

  • 멤버 함수 begin/end
  • 일반 함수 begin/end(C++11 이상)
    • 표준 배열까지 동일 코드로 사용 가능한 일반 함수 버전 사용을 권장
#include <iostream>
#include <vector>
#include <list>

int main()
{
    std::list<int> s1 = { 1,2,3,4,5,6,7,8,9,10 }; // 리스트 선언
    auto s1b = s1.begin(); // 첫번째 요소
    auto s1e = s1.end(); // 마지막 다음 요소.

    while (s1b != s1e) // 모든 요소 읽기
    {
        int n = *s1b;
        ++s1b;
    }

    std::vector<int> s2 = { 1,2,3,4,5,6,7,8,9,10 }; // vector 선언
    auto s2b = s1.begin(); // 첫번째 요소
    auto s2e = s1.end(); // 마지막 다음요소.

    while (s2b != s2e) // 모든 요소 읽기
    {
        int n = *s2b;
        ++s2b;
    }

    int s3[] = { 1,2,3,4,5,6,7,8,9,10 }; // 배열 선언
    auto s3b = std::begin(s3); // 첫번째 요소(일반 함수) C++11, 멤버보단 일반 함수 권장
    auto s3e = std::end(s3); // 마지막 다음요소(일반 함수) C++11
}

전체 요소 접근 방법

  1. [] 연산자 사용 : vector, deque 사용 가능, list 사용 불가
  2. range fo 사용
  3. while 사용
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };

    // 1. [] 연산자, vector는 되지만 list는 안됨
    for (int i = 0; i < v.size(); i++)
    {
        std::cout << v[i] << std::endl;
    }

    // 2. range for, 모든 집합 타입 가능
    for (auto& n : v)
        std::cout << n << std::endl;

    // 3. 반복자 사용, 모든 집합 타입 가능
    auto p1 = std::begin(v);
    while (p1 != std::end(v))
    {
        std::cout << *p1 << std::endl;
        ++p1;
    }

}

반복자의 장점

  • 컨테이너의 내부 자료구조에 상관없이 동일한 방법으로 모든 요소를 접근 할 수 있음
  • GoF's 디자인 패턴중 "iterator" 패턴 활용
#include <iostream>
#include <vector>
#include <list>

int main()
{
    std::list<int> s = { 1,2,3,4,5 }; // 비순차 메모리 주소 알고리즘
    std::vector<int> v = { 1,2,3,4,5 }; // 순차 메모리 주소 알고리즘

    auto p1 = std::begin(s); // 자료구조 무관 동일 접근
    auto p2 = std::begin(v); // 자료구조 무관 동일 접근
    
    ++p1;
    ++p2;

    int n1 = *p1;
    int n2 = *p2;
}
반응형

반응형

list, vector, tree 등 여러개의 데이터를 보관하는 자료구조

  • 특징
    • 배열은 크기 변경이 불가능 하지만 STL vector는 크기 변경 가능
  • 통일된 멤버 함수
    • 대부분 코드 수정 없이 컨테이너 교체 가능
    • 요소 삽입 : push_front, push_back, insert
    • 요소 제거 : pop_front, pop_back, erase
    • 요소 접근 : front, back
    • vector는 앞에 삽입할 수 없다.(push_fron 함수 x)
  • 주의사항
    • pop_back : 제거만 하고 리턴 하지 않음
    • back : 리턴만 하고 제거하지 않음
#include <iostream>
#include <vector>
#include <list>

int main()
{
    int x[10];
    std::vector<int> v(10);
    v.resize(5);

    std::list<int> s1 = { 1,2,3 };
    std::vector<int> s2 = { 1, 2, 3 };

    s1.push_front(10);
    s1.push_back(10);
    s1.push_back(10);
    s1.pop_back();

    int n2 = s1.back();
    int n3 = s1.back();
    s1.pop_back();
    int n4 = s1.back();
}

 

  • array
    • <array>
    • C의 배열과 유사한 자료구조
  • vector
    • <vector>
    • 크기를 변경할 수 있는 동적 배열
  • list
    • <list>
    • 더블 리스트
  • forward_list
    • <forward_list>
    • 싱글 리스트
  • deque
    • <deque>
    • list와 vectort의 혼합형 자료구조
  • set
    • <set>
    • tree
  • map
    • <map>
    • tree를 사용해서 key와 data 저장
  • unordered_set
    • <unordered_set>
    • hash
  • unordered_map
    • <unordered_map>
    • hash를 사용해서 key와 data 저장
  • stack
    • <stack>
    • 스택
  • queue
    • <queue>
  • priority_queue
    • <queue>
    • 우선순위 큐
반응형

반응형

C++ 언어가 제공하는 템플릿 기반의 표준 라이브러리

  • C++ 탄생(197x ~1980)
    • 연구실용 언어로 사용
  • C++98/03(1998 ~ 2003)
    • 자료구조를 나타내는 컨테이너, 알고리즘 함수, 반복자, 함수 객체등 포함
  • C++11/14(2011 ~ 2014)
    • Hash, 스마트 포인터, 멀티스레드, atomic, regex, chrono, bind, function 등
  • C++17(2017)
    • File System, Optional, Any, string_view, array_view
  • C++20(2020)
    • 병렬 프로그래밍, Concept 개념
    • www.isocpp.org 참고
반응형

반응형

생성자와 연산자 재정의를 이용한 String 클래스 만들기

class String
{
    char* buff; // 문자열 버퍼
    int size; // 문자열 사이즈
public:
    String(const char* s) // 생성자
    {
        size = strlen(s);
        buff = new char[size + 1];
        strcpy(buff, s);
    }
    ~String() { delete[] buff;}

    String(const String& s) : size(s.size) // 복사 생성자(여기선 깊은 복사)
    {
        buff = new char[size + 1];
        strcpy(buff, s.buff);
    }

    String& operator=(const String& s) // 대입 연산자 재정의
    {
        // 자신과의 대입 조사
        if (&s == this)
            return *this;

        size = s.size;

        delete[] buff; // 기존 메모리 해지
        buff = new char[size + 1]; // 대입받는 문자열 사이즈로 메모리 동적 할당
        strcpy(buff, s.buff);

        return *this;
    }

    friend std::ostream& operator<<(std::ostream& os, const String& s); // 멤버 외부 접근용 friend 선언
};

std::ostream& operator<<(std::ostream& os, const String& s)
{
    os << s.buff;
    return os; 
}

int main()
{
    String s1 = "apple"; // 복사 생성자
    String s2 = "banana"; // 복사 생성자

    s1 = s2; // 대입 연산자 지원
    s1 = s1; // 자신에 대한 대입 연산자 지원

    std::cout << s1 << std::endl; // cout 출력 지원
}
반응형

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

C++ STL 컨테이너(Container)  (0) 2019.05.11
C++ STL(Standard Template Library)  (0) 2019.05.11
C++ 대입 연산자(assignment)  (0) 2019.05.10
C++ 스마트 포인터(Smart Pointer)  (0) 2019.05.10
C++ 증감 연산자(++, --)  (0) 2019.05.10

반응형
  • 대입 연산자
    • 객체의 멤버를 모두 복사해주는 연산자
  • 생성하지 않을경우 컴파일러가 자동으로 제공하는 멤버들
    • 기본 생성자
    • 소멸자
    • 복사 생성자(Shallow Copy)
    • 대입 연산자
    • move 생성자
    • move 대입 연산자
class Point
{
    int x, y;
public:
    Point(int a = 0, int b = 0) : x(a), y(b) {}

    void print() const
    {
        std::cout << x << ", " << y << std::endl;
    }

    Point& operator=(const Point& p)
    {
        x = p.x;
        y = p.y;

        return *this;
    }

};

int main()
{
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3;
    p3 = (p1 = p2);

    (p3 = p1) = p2; // 대입 연산자가 참조 리턴을 하지 않으면 p3에 p2가 대입되지 않음

    p3.print();

}
반응형

반응형
  • 스마트 포인터
    • 다른 타입의 포인터 역할을 하는 객체
  • 구현 원리
    • ->, * 연산자 재정의를 통해 포인터 처럼 보이게 함
    • * 연산자 재정의 할때는 반드시 참조 리턴
  • 장점
    • 객체이므로 생성자/복사생성자/대입연산자/소멸자 등을 통해서 생성/복사/대입/소멸의 과정을 제어 가능
    • 소멸자에서 동적 할당 자원 해지

스마트 포인터 직접 구현

class Car
{
public:
    void Go() { std::cout << "Go" << std::endl; }
    ~Car() { std::cout << "~Car" << std::endl; }
};

class SPtr // Car 포인터를 소유한 객체(스마트 포인터)
{
    Car* ptr;
public:
    SPtr(Car* p = 0) : ptr(p) {}
    Car* operator->() { return ptr; }
    Car& operator*() { return *ptr; }
};

int main()
{
    SPtr p = new Car; // SPtr p( new Car ) 원리
    p->Go(); // (p.operator->())->Go() 원리
    (*p).Go(); // (p.operator*())->Go() 원리
}

스마트 포인터 직접 구현<템플릿 버전>

  • 아래의 코드도 얕은 복사(Shallow Copy) 이슈는 있음
// 다양한 데이터 타입 지원을 위한 템플릿 활용
template<typename T>
class SPtr
{
    T* ptr;
public:
    SPtr(T* p = 0) : ptr(p) {}
    ~SPtr() { delete ptr; }
    T* operator->() { return ptr; }
    T& operator*() { return *ptr; }
    void print() { std::cout << *ptr << std::endl; }
};

int main()
{
    SPtr<int> p1 = new int; // SPtr<int> p( new int ) 원리
    *p1 = 10;
    p1.print();
}

C++ 표준 스마트 포인터 사용

  • Shared_ptr
    • C++ 표준 스마트 포인터
    • <memory> 헤더
    • 참조 계수 기반으로 구현됨
  • 주의사항
    • shared_ptr<Car> p1 = new Car; // error
    • shared_ptr<Car> p1 ( new Car ); // ok
    • explicit 생성자 때문에 = 사용 불가
#include <iostream>
#include <memory> // shared_ptr을 사용하기 위해

class Car
{
public:
    void Go() { std::cout << "Go" << std::endl; }
    ~Car() { std::cout << "~Car" << std::endl; }
};

int main()
{
    std::shared_ptr<Car> p(new Car); // = 생성자는 지원하지 않음

    p->Go();
}
반응형

반응형

연산자 재정의 활용

  • 전위형(++n), 후위형(n++) 연산자
    • 전위형, 후위형 모두 n.operator++ 연산자 재정의로 구현
    • 전위형은 자신을 참조로 리턴하여 구현
      • Integer& operator++()
    • 후위형은 구분을 위해 인자로 int를 받고 리턴값으로 증감을 반영하지 않기 위해 값으로 리턴
    • 후위형은 내부에서 전위형을 호출(재활용)하여 구현 
      • Integer operator++(int)
class Integer
{
    int value;
public:
    Integer(int n = 0) : value(n) {}

    void print() const
    {
        std::cout << value << std::endl;
    }

    // 전위형 - 값리턴.
    Integer& operator++()
    {
        ++value;
        return *this;
    }

    // 후위형 - 값리턴.
    Integer operator++(int)
    {
        Integer temp = *this;
        ++(*this); // 전위형 코드를 호출하여 재활용
        return temp;
    }
};

int main()
{
    Integer n1 = 2;
    Integer n2 = ++n1; // 전위 연산자 return : 3
    Integer n3 = 2; 
    Integer n4 = n3++; // 후위 연산자 return : 2

    n2.print();
    n4.print();
}
반응형

반응형

연산자 재정의 활용

함수 객체( Function Object )

  • 정의
    •  () 연산자를 재정의해서 함수처럼 사용 가능한 객체
    • "Function Object" 또는 "Functor" 라고도 부른다.
  • 장점
    • 특정 상황(다른 함수의 인자로 전달 될 때)에서는 일반 함수보다 빠르다(인라인 치환)
    • 상태를 가지는 함수( 멤버 데이터가 있고, 멤버 함수를 활용 가능)
struct Plus
{
    int operator()(int a, int b)
    {
        return a + b;
    }
};

int main()
{
    Plus p;
    int n = p(1, 2); // 함수 처럼 사용

    std::cout << n << std::endl; // p.operator()(1,2)
}

///////////////////////////////////////////////////////
// 모든 데이터 타입 지원을 위한 템플릿 적용 버전
template<typename T>
struct Plus
{
    T operator()(T a, T b)
    {
        return a + b;
    }
};

int main()
{
    Plus<int> p;
    int n = p(1, 2); // 함수 처럼 사용

    std::cout << n << std::endl; // p.operator()(1,2)
}

C++ 표준 함수 객체

  • <functional> 헤더
  • 이미 plus, minus, module, less, greater 등 다양하게 제공
  • C++ 레퍼런스 사이트 참고(http://www.cppreference.com)
#include <iostream>
#include <functional>

int main()
{
    std::plus<int> p;
    int n = p(1, 2); // 함수 처럼 사용
}

 

반응형

+ Recent posts