어떤 STL
컨테이너 처럼 작동하는 새 컨테이너를 작성하는 방법에 대한 지침이 있습니까?
답변
여기에 그 § 23.2.1 \ 4 주에서 함께 조합해서 일련의 의사 컨테이너 I의 iterator_category
중 하나 여야는 std::input_iterator_tag
, std::output_iterator_tag
, std::forward_iterator_tag
, std::bidirectional_iterator_tag
, std::random_access_iterator_tag
. 또한 아래 내용은 기술적으로 필요한 것보다 더 엄격하지만 이것이 아이디어입니다. 대부분의 “표준”함수는 반복 자라는 멋진 기능으로 인해 기술적으로 선택 사항입니다.
template <class T, class A = std::allocator<T> >
class X {
public:
typedef A allocator_type;
typedef typename A::value_type value_type;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
typedef typename A::difference_type difference_type;
typedef typename A::size_type size_type;
class iterator {
public:
typedef typename A::difference_type difference_type;
typedef typename A::value_type value_type;
typedef typename A::reference reference;
typedef typename A::pointer pointer;
typedef std::random_access_iterator_tag iterator_category; //or another tag
iterator();
iterator(const iterator&);
~iterator();
iterator& operator=(const iterator&);
bool operator==(const iterator&) const;
bool operator!=(const iterator&) const;
bool operator<(const iterator&) const; //optional
bool operator>(const iterator&) const; //optional
bool operator<=(const iterator&) const; //optional
bool operator>=(const iterator&) const; //optional
iterator& operator++();
iterator operator++(int); //optional
iterator& operator--(); //optional
iterator operator--(int); //optional
iterator& operator+=(size_type); //optional
iterator operator+(size_type) const; //optional
friend iterator operator+(size_type, const iterator&); //optional
iterator& operator-=(size_type); //optional
iterator operator-(size_type) const; //optional
difference_type operator-(iterator) const; //optional
reference operator*() const;
pointer operator->() const;
reference operator[](size_type) const; //optional
};
class const_iterator {
public:
typedef typename A::difference_type difference_type;
typedef typename A::value_type value_type;
typedef typename const A::reference reference;
typedef typename const A::pointer pointer;
typedef std::random_access_iterator_tag iterator_category; //or another tag
const_iterator ();
const_iterator (const const_iterator&);
const_iterator (const iterator&);
~const_iterator();
const_iterator& operator=(const const_iterator&);
bool operator==(const const_iterator&) const;
bool operator!=(const const_iterator&) const;
bool operator<(const const_iterator&) const; //optional
bool operator>(const const_iterator&) const; //optional
bool operator<=(const const_iterator&) const; //optional
bool operator>=(const const_iterator&) const; //optional
const_iterator& operator++();
const_iterator operator++(int); //optional
const_iterator& operator--(); //optional
const_iterator operator--(int); //optional
const_iterator& operator+=(size_type); //optional
const_iterator operator+(size_type) const; //optional
friend const_iterator operator+(size_type, const const_iterator&); //optional
const_iterator& operator-=(size_type); //optional
const_iterator operator-(size_type) const; //optional
difference_type operator-(const_iterator) const; //optional
reference operator*() const;
pointer operator->() const;
reference operator[](size_type) const; //optional
};
typedef std::reverse_iterator<iterator> reverse_iterator; //optional
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; //optional
X();
X(const X&);
~X();
X& operator=(const X&);
bool operator==(const X&) const;
bool operator!=(const X&) const;
bool operator<(const X&) const; //optional
bool operator>(const X&) const; //optional
bool operator<=(const X&) const; //optional
bool operator>=(const X&) const; //optional
iterator begin();
const_iterator begin() const;
const_iterator cbegin() const;
iterator end();
const_iterator end() const;
const_iterator cend() const;
reverse_iterator rbegin(); //optional
const_reverse_iterator rbegin() const; //optional
const_reverse_iterator crbegin() const; //optional
reverse_iterator rend(); //optional
const_reverse_iterator rend() const; //optional
const_reverse_iterator crend() const; //optional
reference front(); //optional
const_reference front() const; //optional
reference back(); //optional
const_reference back() const; //optional
template<class ...Args>
void emplace_front(Args&&...); //optional
template<class ...Args>
void emplace_back(Args&&...); //optional
void push_front(const T&); //optional
void push_front(T&&); //optional
void push_back(const T&); //optional
void push_back(T&&); //optional
void pop_front(); //optional
void pop_back(); //optional
reference operator[](size_type); //optional
const_reference operator[](size_type) const; //optional
reference at(size_type); //optional
const_reference at(size_type) const; //optional
template<class ...Args>
iterator emplace(const_iterator, Args&&...); //optional
iterator insert(const_iterator, const T&); //optional
iterator insert(const_iterator, T&&); //optional
iterator insert(const_iterator, size_type, T&); //optional
template<class iter>
iterator insert(const_iterator, iter, iter); //optional
iterator insert(const_iterator, std::initializer_list<T>); //optional
iterator erase(const_iterator); //optional
iterator erase(const_iterator, const_iterator); //optional
void clear(); //optional
template<class iter>
void assign(iter, iter); //optional
void assign(std::initializer_list<T>); //optional
void assign(size_type, const T&); //optional
void swap(X&);
size_type size() const;
size_type max_size() const;
bool empty() const;
A get_allocator() const; //optional
};
template <class T, class A = std::allocator<T> >
void swap(X<T,A>&, X<T,A>&); //optional
또한 컨테이너를 만들 때마다 다음과 같이 클래스로 테스트합니다.
#include <cassert>
struct verify;
class tester {
friend verify;
static int livecount;
const tester* self;
public:
tester() :self(this) {++livecount;}
tester(const tester&) :self(this) {++livecount;}
~tester() {assert(self==this);--livecount;}
tester& operator=(const tester& b) {
assert(self==this && b.self == &b);
return *this;
}
void cfunction() const {assert(self==this);}
void mfunction() {assert(self==this);}
};
int tester::livecount=0;
struct verify {
~verify() {assert(tester::livecount==0);}
}verifier;
tester
개체의 컨테이너를 만들고 컨테이너 function()
를 테스트 할 때 각 개체를 호출 합니다. 전역 tester
개체를 만들지 마십시오 . 컨테이너가 어디에서나 속이는 경우,이 tester
클래스는 assert
실수로 어딘가에서 속임수를 썼다는 것을 알게 될 것입니다.
답변
컨테이너 구현을 위해 C ++ 표준이 부과하는 컨테이너 및 요구 사항에 대한 C ++ 표준 섹션을 읽어야합니다.
C ++ 03 표준의 관련 장은 다음과 같습니다.
섹션 23.1 컨테이너 요구 사항
C ++ 11 표준의 관련 장은 다음과 같습니다.
섹션 23.2 컨테이너 요구 사항
C ++ 11 표준의 최종 초안은 여기에서 무료로 사용할 수 있습니다 .
컨테이너 사용자의 관점에서 요구 사항을 이해하는 데 도움이되는 훌륭한 책을 읽을 수도 있습니다. 내 마음에 쉽게 떠오른 두 가지 훌륭한 책은 다음과 같습니다.
효과적인 STL 에 의해스콧 마이어스 및
튜토리얼 및 참조 : C ++ 표준 라이브러리 에 의해니콜라이 Josutils
답변
다음은 기본적으로 래퍼 std::vector
이며 STL 반복기를 모방하는 자체 (그러나 실제) 반복기 를 갖는 가짜 벡터의 매우 단순한 구현입니다 . 다시 말하지만, 이터레이터는 const_iterator
, 유효성 검사 등과 같은 많은 개념을 건너 뛰는 매우 단순 합니다.
코드는 즉시 실행할 수 있습니다.
#include <iostream>
#include <string>
#include <vector>
template<typename T>
struct It
{
std::vector<T>& vec_;
int pointer_;
It(std::vector<T>& vec) : vec_{vec}, pointer_{0} {}
It(std::vector<T>& vec, int size) : vec_{vec}, pointer_{size} {}
bool operator!=(const It<T>& other) const
{
return !(*this == other);
}
bool operator==(const It<T>& other) const
{
return pointer_ == other.pointer_;
}
It& operator++()
{
++pointer_;
return *this;
}
T& operator*() const
{
return vec_.at(pointer_);
}
};
template<typename T>
struct Vector
{
std::vector<T> vec_;
void push_back(T item)
{
vec_.push_back(item);
};
It<T> begin()
{
return It<T>(vec_);
}
It<T> end()
{
return It<T>(vec_, vec_.size());
}
};
int main()
{
Vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
bool first = true;
for (It<int> it = vec.begin(); it != vec.end(); ++it)
{
if (first) //modify container once while iterating
{
vec.push_back(4);
first = false;
}
std::cout << *it << '\n'; //print it
(*it)++; //change it
}
for (It<int> it = vec.begin(); it != vec.end(); ++it)
{
std::cout << *it << '\n'; //should see changed value
}
}