Herhangi bir STL
konteyner gibi davranacak yeni bir konteynerin nasıl yazılması gerektiğine dair yönergeler var mı?
Herhangi bir STL
konteyner gibi davranacak yeni bir konteynerin nasıl yazılması gerektiğine dair yönergeler var mı?
Yanıtlar:
İşte bu § 23.2.1 \ 4 Not araya getirilmiş bir dizi sözde kap, bu iterator_category
biri olmalıdır std::input_iterator_tag
, std::output_iterator_tag
, std::forward_iterator_tag
, std::bidirectional_iterator_tag
, std::random_access_iterator_tag
. Ayrıca aşağıdakilerin teknik olarak gerekenden daha katı olduğunu unutmayın , ancak fikir budur. "Standart" işlevlerin büyük çoğunluğunun, yineleyiciler olan mükemmelliğinden dolayı teknik olarak isteğe bağlı olduğunu unutmayın.
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
Ayrıca, ne zaman bir konteyner yapsam, aşağı yukarı bunun gibi bir sınıfla test ederim:
#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
Nesnelerin kaplarını yapın ve kabınızı function()
test ederken her birini çağırın . Herhangi bir global tester
nesne yapmayın . Eğer konteynırınız herhangi bir yerde hile yapıyorsa , bu tester
sınıf hile yapacak assert
ve yanlışlıkla bir yerde kopya çektiğinizi bileceksiniz.
assert(tester::livecount == 0);
. Mmmmm, hala bu test yapısının nasıl çalıştığından emin değilim. Bir örnek verebilir misiniz?
memcpy
olmadığını kontrol etmenin bir yoludur . (test kusursuz değildir, ancak bazılarını yakalar). livecount
Emin konteyner yapıcılar ve yıkıcılar eşit sayıda denilen yapmak, basit bir sızıntı dedektörüdür.
verifier
değildir varifier
.
std::iterator
başlıktan devralmayı önerebilir miyim<iterator>
Kapsayıcılar ve C ++ Standardının kapsayıcı uygulamaları için uyguladığı gereksinimler hakkındaki C ++ Standardı bölümünü okumanız gerekir.
C ++ 03 standardında ilgili bölüm şudur:
Bölüm 23.1 Konteyner Gereksinimleri
C ++ 11 standardındaki ilgili bölüm şudur:
Bölüm 23.2 Konteyner Gereksinimleri
C ++ 11 standardının neredeyse son taslağı ücretsiz olarak burada mevcuttur .
Ayrıca, konteynerin kullanıcısı açısından gereksinimleri anlamanıza yardımcı olacak bazı mükemmel kitaplar da okuyabilirsiniz. Aklıma gelen iki harika kitap:
Etkili STL ,Scott Meyers &
The C ++ Standard Library: A Tutorial and Reference byNicolai Josutils
Burada, temelde bir sarmalayıcı std::vector
olan ve STL yineleyicisini taklit eden kendi (ama gerçek) yineleyicisine sahip olan sahte bir vektörün çok basit bir uygulaması . Yineleyici çok basittir ve aşağıdaki gibi birçok kavramı atlar:const_iterator
, geçerlilik kontrolleri vb. .
Kod kutudan çıkarılabilir.
#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
}
}