C++ 编写自己的 STL 容器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7758580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Writing your own STL Container
提问by Avinash
Are there guidelines on how one should write new container which will behave like any STL
container?
是否有关于如何编写新容器的指南,该容器将像任何STL
容器一样运行?
回答by Mooing Duck
Here's a sequence pseudo-container I pieced together from § 23.2.1\4 Note that the iterator_category
should be one of std::input_iterator_tag
, std::output_iterator_tag
,std::forward_iterator_tag
,std::bidirectional_iterator_tag
,std::random_access_iterator_tag
. Also note that the below is technicallymore strict than required, but this is the idea. Note that the vast majority of the "standard" functions are technically optional, due to the awesomeness that is iterators.
这是我从 § 23.2.1\4 拼凑起来的一个序列伪容器 注意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
Also, whenever I make a container, I test with a class more or less like this:
此外,每当我制作容器时,我都会或多或少地用这样的类进行测试:
#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;
Make containers of tester
objects, and call each one's function()
as you test your container. Do not make any global tester
objects. If your container cheats anywhere, this tester
class will assert
and you'll know that you cheated accidentally somewhere.
制作tester
对象的容器,并function()
在测试容器时调用每个对象。不要创建任何全局tester
对象。如果你的容器在任何地方作弊,这个tester
类会assert
并且你会知道你在某个地方不小心作弊。
回答by Alok Save
You will need to read the C++ Standard section about Containers and requirements the C++ Standard imposes for container implementations.
您将需要阅读有关容器和 C++ 标准对容器实现强加的要求的 C++ 标准部分。
The relevant chapter in C++03 standard is:
C++03标准中的相关章节是:
Section 23.1 Container Requirements
第 23.1 节容器要求
The relevant chapter in C++11 standard is:
C++11标准中的相关章节是:
Section 23.2 Container Requirements
第 23.2 节容器要求
The near-final draft of the C++11 standard is freely available here.
C++11 标准的接近最终草案可在此处免费获得。
You might as well, read some excellent books which will help you understand the requirements from an perspective of user of the container. Two excellent books which struck my mind easily are:
您不妨阅读一些优秀的书籍,这些书籍将帮助您从容器用户的角度理解需求。我很容易想到的两本好书是:
Effective STLby Scott Meyers&
The C++ Standard Library: A Tutorial and Referenceby Nicolai Josutils
有效STL通过斯科特迈尔斯&
教程和参考:C ++标准库由尼古拉Josutils
回答by PoweredByRice
Here is a very simplistic implementation of a fake vector, which is basically a wrapper around std::vector
and has its own (but real) iterator, which mimics the STL iterator. Again, the iterator is very simplistic, skipping over many concepts like const_iterator
, validity checks etc.
这是一个非常简单的伪向量实现,它基本上是一个包装器,std::vector
并有自己的(但真实的)迭代器,它模仿 STL 迭代器。同样,迭代器非常简单,跳过了许多概念,例如const_iterator
有效性检查等。
Code is runnable out of the box.
代码开箱即用。
#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
}
}