헤더파일

반복자 본문

C++

반복자

헤더파일 2018. 5. 21. 15:19

template<typename T>

void f(T a, T b)

{

auto temp = *a;

*a = *b;

*b = temp;

}


int main()

{

vector<int> v{ 1,2,3,4,5 };

//f는 두 반복자가 가리키는 값을 교환하는 함수

f(v.begin(), v.end() - 1);


for (auto& data : v)

{

cout << data << endl;

}

return 0;

}


여기서 반복자의 크기는 4바이트 이므로 레퍼런스 붙이는 건 의미가 없습니다. 

알아야할껀 템플릿 함수는 컴파일 할 때 코드를 찍어내므로 빨간줄이 안 그어집니다. 변수형을 지정안하고 temp = *a 이렇게 써도 코드 작성중에는 문제가 있는지 안 알려줍니다.


하지만 temp의 자료형은 auto를 안 쓰면 어떻게 알 수 있을까요?

반복자는 자료구조와 알고리즘을 이어줄려는 목적으로 쓴다. 알고리즘 입장에서는 자료구조가 어떻게 메오리가 구성되어 있는지 알 필요없기 때문입니다. find함수 입장에서는 주어진 범위를 돌아다니기만 하면됩니다. find함수거나 다른 함수인데 전달되는 반복자가 어떤 자료구조에서 나온건지 표시 할 수 있다면 더 좋게 만들 수 있습니다.  


모든 STL반복자는 특성을 정의해야 합니다.

1.어떤 형태의 반복자니?

2.포인터로 바꾸면 어떤 포인터니?

3.레퍼런스로 바꾸면 어떤 타입이니?

4.너가 가리키고 있는 타입은 뭐니?

5.너랑 다른 반복자와 거리를 재면 무슨 값이니?


그래서 STL은 iterator_traits라는 클래스를 제공하는데 

typename iterator_traits<T>::value_type temp = *a; 

처럼 써서 자료형을 얻어올 수도 있고 여러 정보를 얻어올 수 있습니다.


typename iterator_traits<T>::iterator_category c;

cout << typeid(c).name() << endl;


벡터의 반복자를 넘겨준다면 이렇게 카테고리를 줍니다. -> struct std::random_access_iterator_tag

포인터를 넘겨도 -> struct std::random_access_iterator_tag

리스트를 넘기면 -> struct std::bidirectional_iterator_tag



반복자를 이용해서 컨테이너의 크기를 얻어 봅시다.


메모리가 연속적인 random_access라면 

int MyDist(Iter begin, Iter end)

{

return end - begin;

}

-연산자로 구할 수 있습니다.


하지만 list같은 메모리 구조라면 이런 형태로 구할 수 없습니다.


template<typename Iter>

int MyDist(Iter begin, Iter end)

{

typename iterator_traits<Iter>::iterator_category c;

if (string(typeid(c).name()) == "struct std::random_access_iterator_tag")

{

cout << "랜덤 액세스의 반복자다!" << endl;

return end - begin;

}

int cnt = 0;

while (begin != end)

{

cnt++;

begin++;

}

return cnt;

}


이렇게 if문으로 걸러주면 될꺼 같지만 템플릿 함수는 판을 찍을 때 분기를 고려하지 않고 찍어 무조건 retun end - begin이 호출됩니다.

template<class Iter>
int MyDist(Iter begin, Iter end, random_access_iterator_tag)
{
return end - beg;
}
template<class Iter>
int MyDist(Iter begin, Iter end, forward_iterator_tag)
{
int cnt = 0;
while (begin != end)
{
cnt++;
begin++;
}
return cnt;
}

template<typename Iter>
int MyDist(Iter begin, Iter end)
{
return MyDist(begin, end, iterator_traits<Iter>::iterator_category());
}


오버로딩을 이용해 작성해야 합니다. 오버로딩 된 함수의 세번째 인자는 판단용으로만 씁니다 전위, 후위 연산자를 오버로딩 할 때 사용하는 방식입니다. 




STL 클래스인 String 클래스를 직접 작성해보고 반복자 구현하기!



class myString
{
public:
myString() = default;
myString(const char* text)
{
len = strlen(text);
p = new char[len+1];
strcpy(p, text);
}
myString(const myString& s)
{
cout << "복사연산!"<<endl;
delete p;
p = nullptr;

len = strlen(s.p);
p = new char[len + 1];
strcpy(p, s.p);
}
~myString() { delete p; p = nullptr; }

char* getChar() { return p; }
friend ostream& operator<<(ostream& os, const myString& s);

myString operator=(const myString& s)
{
cout << "대입연산!" << endl;
delete p;
p = nullptr;

len = strlen(s.p);
p = new char[len + 1];
strcpy(p, s.p);
return *this;
}

myString operator+(const char* s)
{
int size = len + strlen(s);
char* temp;
temp = new char[size];
strcpy(temp, p);
strcat(temp, s);

myString returnData{temp};

return returnData;
}
myIterator begin()
{
return myIterator(p);
}
myIterator end()
{
return myIterator(p + len);
}

private:
char* p = nullptr;
int len = 0;
};

ostream& operator<<(ostream& os, const myString& s)
{
os << s.p<<endl;
return os;
}




int main()
{
vector<int>::iterator t;
myString s{ "Hello STL!" };
myString s1=s;
myString s2 = s1 + "안녕, STL!";
cout << s;
cout << s1;
cout << s2;
}

String 클래스에서 지원하는 +, =, begin, end 를 만들어줍니다. 

이제 반복자를 만들어보겠습니다.

반복자가 해줘야 할 동작은
*연산자 - 역참조 동작, 가리키는 원소를 역참조해서 리턴
==연산자 - 
=연산자 - 


또 표준 반복자라면 iterator_traits<반복자>::iterator_category변수를 가져야 합니다.



class myRevIterator : public iterator<random_access_iterator_tag, char> {

char* p;

public:

myRevIterator(char* p) : p{ p } {

}

char& operator*() {

char c = *(p - 1);

return c;

}

myRevIterator operator++() {

--p;

return *this;

}

bool operator!=(const myRevIterator& other)const {

return p != other.p;

}

};


class myIterator : public iterator<random_access_iterator_tag, char> {

char* p;

public:

myIterator(char* p) : p{ p } {

}

char& operator*() {

return *p;

}

bool operator==(const myIterator& other) {

return p == other.p;

}

bool operator!=(const myIterator& other) {

return p != other.p;

}

void operator=(const myIterator& other) {

p = other.p;

}

myIterator& operator++() {

++p;

return *this;

}

myIterator operator++(int) {

myIterator temp(p);

++p;

return temp;

}


//랜덤 엑세스 반복자가 지원하는 연산들

int operator-(const myIterator& rhs) const { return p - rhs.p; }

myIterator operator+(int n) const {

myIterator temp(p);

temp.p += n;

return temp;

}

bool operator<(const myIterator& rhs)const {

return *p < *rhs.p;

}

myIterator operator-(int n) {

myIterator temp(p);

temp.p -= n;

return temp;

}


myIterator& operator--() {

--p;

return *this;

}

myIterator operator--(int) {

myIterator temp(p);

--p;

return temp;

}

};


class myString {

char* p;

int len;

public:

using iterator = myIterator;


myString(const char* s) {

len = strlen(s);

p = new char[len + 1];

strcpy(p, s);

}

myString(const myString& other)

{

len = other.len;

p = new char[len + 1];

strcpy(p, other.p);

}

myString& operator=(const myString& other)

{

len = other.len;

p = new char[len + 1];

strcpy(p, other.p);

delete[] p;

}

myString operator+(const char*s)

{

int num = len + strlen(s);

char* q = new char[num + 1];

strcpy(q, p);

strcat(q, s);

myString m(q);

delete[] q;

return m;

}

~myString()

{

delete[] p;

}

myIterator begin() {

return myIterator(p);

}

myIterator end() {

return myIterator(p + len);

}

myRevIterator rbegin() {

return myRevIterator(p + len);

}

myRevIterator rend() {

return myRevIterator(p);

}


friend ostream& operator<<(ostream&, const myString&);

};


ostream& operator<<(ostream& os, const myString& s)

{

os << s.p;

return os;

}



int main()

{

myString s{ "Hello,STL!" };

for (auto p = s.rbegin(); p != s.rend(); ++p)

cout << *p << ' ';

cout << endl;

//sort(s.begin(),s.end());

//for (auto d : s) {

//   cout << d ;

//}

//cout << endl;

}


'C++' 카테고리의 다른 글

문자열 함수  (0) 2018.06.11
알고리즘 함수  (0) 2018.05.31
Map을 이용한 파일입출력  (0) 2018.05.14
연관 컨테이너  (0) 2018.04.30
노말분포 & 시퀀스 컨테이너  (0) 2018.04.16
Comments