Có hướng dẫn về cách người ta nên viết vùng chứa mới sẽ hoạt động giống như bất kỳ vùng STL
chứa nào không?
Có hướng dẫn về cách người ta nên viết vùng chứa mới sẽ hoạt động giống như bất kỳ vùng STL
chứa nào không?
Câu trả lời:
Dưới đây là một chuỗi pseudo-container Tôi chắp ghép từ § 23.2.1 \ 4 Lưu ý rằng iterator_category
nên là một trong std::input_iterator_tag
, std::output_iterator_tag
, std::forward_iterator_tag
, std::bidirectional_iterator_tag
, std::random_access_iterator_tag
. Cũng lưu ý rằng bên dưới về mặt kỹ thuật nghiêm ngặt hơn so với yêu cầu, nhưng đây là ý tưởng. Lưu ý rằng phần lớn các hàm "tiêu chuẩn" là tùy chọn về mặt kỹ thuật, do sự tuyệt vời của nó là các trình vòng lặp.
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
Ngoài ra, bất cứ khi nào tôi tạo một vùng chứa, tôi kiểm tra với một lớp ít nhiều như thế này:
#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;
Tạo các hộp chứa các tester
đối tượng và gọi từng đối tượng function()
khi bạn kiểm tra vùng chứa của mình. Không tạo bất kỳ tester
đối tượng toàn cục nào . Nếu container của bạn gian lận ở bất cứ đâu, tester
lớp này sẽ assert
và bạn sẽ biết rằng bạn đã vô tình gian lận ở đâu đó.
assert(tester::livecount == 0);
. Mmmmm, vẫn không chắc cách thức hoạt động của khung trình kiểm tra này. Bạn có thể cho một ví dụ?
memcpy
xảy ra. (thử nghiệm không dễ dàng, nhưng nó bắt được một số). Đây livecount
là một công cụ phát hiện rò rỉ đơn giản, để đảm bảo rằng vùng chứa của bạn được gọi là số lượng hàm tạo và hủy bằng nhau.
verifier
không varifier
.
std::iterator
tiêu đề không<iterator>
Bạn sẽ cần đọc phần Tiêu chuẩn C ++ về Vùng chứa và các yêu cầu mà Tiêu chuẩn C ++ áp đặt cho việc triển khai vùng chứa.
Chương liên quan trong tiêu chuẩn C ++ 03 là:
Phần 23.1 Yêu cầu về container
Chương liên quan trong tiêu chuẩn C ++ 11 là:
Phần 23.2 Yêu cầu về container
Bản nháp gần nhất của tiêu chuẩn C ++ 11 có sẵn miễn phí tại đây .
Bạn cũng có thể đọc một số cuốn sách xuất sắc sẽ giúp bạn hiểu các yêu cầu từ góc độ của người sử dụng vùng chứa. Hai cuốn sách xuất sắc khiến tôi dễ dàng nhận ra là:
STL hiệu quả củaScott Meyers &
Thư viện tiêu chuẩn C ++: Hướng dẫn và tài liệu tham khảo củaNicolai Josutils
Đây là một triển khai rất đơn giản của một vectơ giả, về cơ bản là một trình bao bọc xung quanh std::vector
và có trình vòng lặp (nhưng thực) của riêng nó, bắt chước trình vòng lặp STL. Một lần nữa, trình lặp rất đơn giản, bỏ qua nhiều khái niệm nhưconst_iterator
, kiểm tra tính hợp lệ, v.v.
Mã có thể chạy ra khỏi hộp.
#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
}
}