vector用法总结(定义,操作,方法,注意点)(三)

在某些实作上,当你试图创建一个vector<auto_ptr<T> >的时候,会得到编译期错误。这还是算你幸运;如果不幸运的话,事情看起来很好,直到运行期得到不可预知的行为。总之,标准容器类不能与拷贝构造函数不执行拷贝的类型合作。这也不是auto_ptr的设计目的,并且,标准甚至指出“用auto_ptr实例化标准运行库中的容器会得到未定义的行为。”当你需要异常安全机制时,你应该使用auto_ptr以在退出代码空间时delete指针;auto_ptr是因模拟了自动变量而得名的。你不应该试图在容器类中使用auto_ptr来管理指针;它不可行。

取代auto_ptr,你应该使用一个不同的“智能指针”,引用计数的指针类。带引用计数的指针跟踪多少个指针指向相同的对象。当你构造了一个引用计数指针的拷贝时,计数加1;当你销毁一个引用计数指针时,计数减1。当计数变成0时,指针所指的对象被自动销毁。

写一个引用计数的指针类不是特别困难,但也不是几乎什么都不用做;达到线程安全需要特别的技巧。幸运地是,使用引用计数并不意味着你需要写一个自己的引用计数指针类;几种这样的类已经存在并可免费使用。比如,你能使用Boost的shared_ptr类。我期望 shared_ptr或其它类似的东西将成为C++标准的下个修订版本的组成部分。

当然,引用计数只是一种特别的垃圾回收。像所有形式的垃圾回收,它自动销毁你不再需要的对象。引用计数指针的主要优势是它们易于加入现有系统:share_ptr这样的机制只是一个小的单独的类,你能只在一个较大系统中某个部分中使用它。另一方面,引用计数是垃圾回收的一种最低效的形式(每个指针的赋值和拷贝都需要一些相关的复杂处理),最没有柔性的形式(在两个数据结构拥有互指指针时,你必须小心)。其它形式的垃圾回收在C++程序中工作得同样好。特别地,Boehm conservative garbage collector是免费的、可移植的,并被很好测试过。

如果你使用一个保守的垃圾回收器,你只需要将它链接入程序就可以了。你不需要使用任何特别的指针包装类;只需要分配内存而不用关心delete它。特别地,如果你创建一个vector<T *>,你知道所指向的对象只要vector还存在就不会被delete掉(垃圾回收器绝不会破坏还有指针指向它们的对象),并且你也知道它们将在 vector被销毁后的某个时候delete掉(除非,程序的其它部份仍然引用它们)。

垃圾回收的优势(无论是引用计数还是保守的垃圾回收器,或其它方法)是它让你将对象的生存期处理得完全不确定:你不须要掌握在某个特定时间程序的哪个部份引用了这个对象。另一方面,垃圾回收的缺点也正是这一点!有时你确实知道对象的生存期,或至少知道在程序的某个特定状态结束后对象不应该继续存在。举例来说,你可能创建了一个复杂的分析树;也许它填满了多态对象,也许它是太复杂而无法单独掌握每个节点,但是你能确定在分析完后就将不再需要它们中的任何一个。

从手工管理的vetor<T *>到vector<shared_pointer<T> >到保守的垃圾回收器,我们逐步放弃了vector拥有一组对象的观点;垃圾回收的前提是对象的“所有权”是无关紧要的。在某种意义上,它通过扔掉“所有权”问题而解决了这个难题。

如果你的程序确实有明确定义的状态,那么你可能有理由期望在某个状态结束时销毁一组对象。代替垃圾回收,另外一个可选方法是通过一个arena(WQ注:字典上为“竞技场、舞台”之意,译不好,不译)来分配对象:维护一个对象列表,以便能一次就销毁所有对象。

你可能想知道这个技术和前面提到的技术(遍历容器并为每个元素调用destory())有多大差异。有实质性差异吗?如果没有,让我花了这么多时间的那些危险和限制,又怎么说?

差异很小,但很重要:arena存储了一个对象集,目的是为了在以后delete它们,并且没有其它目的。它可以以标准容器的形式实现,但是它不暴露容器接口。你在vector<T *>上遇到问题是因为你能移除元素,拷贝覆盖元素,和运用泛型算法。Arena是一个强所有权协议。Arena容器为每个它所管理的对象容纳了一个并且只一个指针,并且它拥有所有这些对象;它不允许你移除、复制、覆盖或用选择子遍历它容纳的指针。要使用arena中的对象,你需要在别处存储指向它们的指针--在容器中,在树中,或在任何合适的数据结构中。使用权和所有权完全分离。

arena 是个通用的主意。arena可能简单地是个容器,只要记住别使用不安全的成员函数,或者它可以是个包装类以试图运行得更安全。很多这样的包装类已经被写出来了[注7]。Listing 1是一个arena类的简化例子,使用了一个实现上的技巧以使得不必为每个指针类型使用一个不同的arena类。举例来说,你可能写:

arena a;

...

std::vector<int*> v;

v.push_back(a.create<int>(3));

...

a.destroy_all();

我们几乎回到了起点:使用一个容纳指针的vector,所指向的对象由别处拥有和管理。

3、总结

指针在C++程序中很常见,标准容器同样如此;不用惊奇,它们的组合物,容纳指针容器同样很常见。

新手最大的困难是容纳指针的容器时的所有权问题:应该什么时候delete所指向的对象?处理容纳指针的容器的绝大部分技术都可以归结到一个原则:如果你有一个容纳指针的容器,所指向的对象应该由其它地方所拥有。

如果正在处理非多态对象集(类型为my_type),你应该将对象的值存入容器,比如list<my_type>或deque<my_type>。如果需要,你也以使用第二个容器以存储指向那些对象的指针。

不要试图将auto_ptr放入标准容器。

如果有一组多态对象,你需要用容纳指针的容器来管理它们。(但是,那些指针可以被包装在某种handle类或智能指针类中。)当对象生存期不能预知时,或不重要时,最容易的方法是使用垃圾回收。垃圾回收的两个最简单的选择是引用计数指针类和保守的垃圾回收器。对你来说哪个是最佳选择取决于工具的可用性。

如果你有一组多态对象,并需要控制它们的生存期,最简单的方法是使用arena。一个简单的arena类例子展示于Listing 1。

Listing 1: A simple arena class

#include <vector>

class arena {

private:

struct holder {

virtual ~holder() { }

};

template <class T>

struct obj_holder : public holder {

T obj;

template <class Arg1>

obj_holder(Arg1 arg1)

: obj(arg1) { }

};

std::vector<holder*> owned;

private:

arena(const arena&);

void operator=(const arena&);

public:

arena() { }

~arena() {

destroy_all();

}

template <class T, class Arg1>

T* create(Arg1 arg1) {

obj_holder<T>* p = new obj_holder<T>(arg1);

owned.push_back(p);

return &p->obj;

}

void destroy_all() {

std::vector<holder*>::size_type i = 0;

while (i < owned.size()) {

delete owned[i];

++i;

}

owned.clear();

}

};

四、vector的定义

template<class T, class A = allocator<T> >

class vector {

public:

typedef A allocator_type;

typedef A::size_type size_type;

typedef A::difference_type difference_type;

typedef A::reference reference;

typedef A::const_reference const_reference;

typedef A::value_type value_type;

typedef T0 iterator;

typedef T1 const_iterator;

typedef reverse_iterator<iterator, value_type,

reference, A::pointer, difference_type>

reverse_iterator;

typedef reverse_iterator<const_iterator, value_type,

const_reference, A::const_pointer, difference_type>

const_reverse_iterator;

explicit vector(const A& al = A());

explicit vector(size_type n, const T& v = T(), const A& al = A());

vector(const vector& x);

vector(const_iterator first, const_iterator last,

const A& al = A());

void reserve(size_type n);

size_type capacity() const;

iterator begin();

const_iterator begin() const;

iterator end();

iterator end() const;

reverse_iterator rbegin();

const_reverse_iterator rbegin() const;

reverse_iterator rend();

const_reverse_iterator rend() const;

void resize(size_type n, T x = T());

size_type size() const;

size_type max_size() const;

bool empty() const;

A get_allocator() const;

reference at(size_type pos);

const_reference at(size_type pos) const;

reference operator[](size_type pos);

const_reference operator[](size_type pos);

reference front();

const_reference front() const;

reference back();

const_reference back() const;

void push_back(const T& x);

void pop_back();

void assign(const_iterator first, const_iterator last);

void assign(size_type n, const T& x = T());

iterator insert(iterator it, const T& x = T());

void insert(iterator it, size_type n, const T& x);

void insert(iterator it,

const_iterator first, const_iterator last);

iterator erase(iterator it);

iterator erase(iterator first, iterator last);

void clear();

void swap(vector x);

protected:

A allocator;

};

The template class describes an object that controls a varying-length sequence of elements of type T. The sequence is stored as an array of T.

The object allocates and frees storage for the sequence it controls through a protected
object named allocator, of class A. Such an allocator object must have the same external 
interface asan object of template class allocator. Note that allocator is not copied when the 
object is assigned.

Vector reallocation occurs when a member function must grow the controlled sequence beyond its current storage capacity. Other insertions and erasures may alter various storage addresses within the sequence. In all such cases, iterators or references that point at altered portions of the controlled sequence become invalid.

参考文献

1、http://www.cppblog.com/tgh621

2、http://blog.csdn.net/fm0517

3、MSDN库介绍

4、http://blog.163.com/lgy-047/blog/static/61346565200910921446744

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值