激光炸弹,内存分配器Allocator

C++ Primer 学习笔记_47_STL剖析(二):vector源码剖析、内存分配器Allocator

一、vector初始化源码

通过跟踪一个简单的程序,观察vector初始化的过程,通过调试单步执行

#include 
#include 
using namespace std;

int main()
{
    vector v;
    return 0;
}

1、首先,执行了代码

vector() _NOEXCEPT
        : _Mybase()
        {    // construct empty vector
        }

    explicit vector(const _Alloc& _Al) _NOEXCEPT
        : _Mybase(_Al)
        {    // construct empty vector, allocator
        }

2、执行allocator

    allocator() _THROW0()
        {    // construct default allocator (do nothing)
        }

3、进一步执行

    _Vector_alloc(const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al)
        {    // construct allocator from _Al
        _Alloc_proxy();
        }

4、分配内存,初始化为0,经过一连串的调用,初始化结束

    _Vector_val()
        {    // initialize values
        _Myfirst = pointer();
        _Mylast = pointer();
        _Myend = pointer();
        }

    pointer _Myfirst;    // pointer to beginning of array
    pointer _Mylast;    // pointer to current end of sequence
    pointer _Myend;    // pointer to end of array
    };

 

二、capacity

1、首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0
是一致的,如下:

template < class _Ty, class _Ax = allocator<_Ty> > //第二参数是有默认参数的
class vector;

2、但在VC2008 中vector 还有基类,如下:

// TEMPLATE CLASS vector
template < class _Ty,
         class _Ax >
class vector
    : public _Vector_val<_Ty, _Ax>
{
};

3、稍微来看一下基类_Vector_val:

// TEMPLATE CLASS _Vector_val
template < class _Ty,
         class _Alloc >
class _Vector_val
    : public _CONTAINER_BASE_AUX_ALLOC<_Alloc>
{
    // base class for vector to hold allocator _Alval
protected:
    _Vector_val(_Alloc _Al = _Alloc())
        : _CONTAINER_BASE_AUX_ALLOC<_Alloc>(_Al), _Alval(_Al)
    {
        // construct allocator from _Al
    }

    typedef typename _Alloc::template
    rebind<_Ty>::other _Alty;

    _Alty _Alval;   // allocator object for values
};

 

4、为了理解_Alty 的类型,还得看一下allocator模板类:

 

template class allocator
{

    template<> class _CRTIMP2_PURE allocator
    {
        // generic allocator for type void
    public:
        template
        struct rebind
        {
            // convert an allocator to an allocator <_Other>
            typedef allocator<_Other> other;
        };
        ....
    };
    ...
};

typedeftypename_Alloc::templaterebind<_Ty>::other_Alty;
整体来看是类型定义,假设现在我们这样使用vector, 那么_Ty 即 int, _Ax
即 allocator,由vector 类传递给基类Vector_val,则_Alloc 即allocator
;可以看到allocator
是allocator模板类的特化,rebind<_Ty>是成员模板类,other是成员模板类中自定义类型,_Ty
即是int , 那么other 类型也就是allocator, 也就是说_Alty
是类型allocator 。_Alty _Alval; 即 基类定义了一个allocator
类型的成员,被vector 继承后以后用于为vector 里面元素分配内存等操作。

如iteratornew_data =alloc.allocate(new_size);
注意,标准的vector::iterator
是以模板类实现的,下面的实现简单地将其等同为指针,实际上真正的iterator
类的实现是内部有一个指针成员,指向容器元素。

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

对比list 的实现,继承它的基类_List_nod 的一个成员
allocator<_Node> _Alnod; 如下:

typename _Alloc::template rebind<_Node>::other _Alnod; //
allocator object for nodes

其中 _Node有三个成员,如下:

_Nodeptr _Next; // successor node, or first element if head

_Nodeptr _Prev; // predecessor node, or last element if head

_Ty _Myval; // the stored value, unused if head

如果是list ,那么_Ty 即是int
类型。双向链表在创建一个新结点时,这样实现:

_Nodeptr _Pnode = this->_Alnod.allocate(1); //
即分配一个节点的空间,返回指向这个节点的指针。

实际上list 还继承另外两个基类的两个成员,如下:

typename _Alloc::template rebind<_Nodeptr>::other _Alptr;//
allocator object for pointers to nodes

typename _Alloc::template rebind<_Ty>::other _Alty _Alval; //
allocator object for values stored in nodes

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

三、vector动态数组内部如何实现连续空间

1、通过跟踪一个简单的程序,观察vector的capacity分配的过程,通过调试单步执行

#include 
#include 
using namespace std;

int main()
{
    vector v;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    v.push_back(1);
    cout << v.capacity() << endl;
    return 0;
}

图片 1

 

capacity 容量的计算方式如下:容量每次增长为原先容量 + 原先容量 / 2;

增长的源码跟踪结果如下:

    size_type _Grow_to(size_type _Count) const
        {    // grow by 50% or at least to _Count
        size_type _Capacity = capacity();

        _Capacity = max_size() - _Capacity / 2 < _Capacity
            ? 0 : _Capacity + _Capacity / 2;    // try to grow by 50%
        if (_Capacity < _Count)
            _Capacity = _Count;
        return (_Capacity);
        }

2、容量跟vector 大小的概念是不一样的,capacity >= size,如下图所示:

图片 2

size 指的是_Mylast – _Myfirst 的区间;capacity 指的是 _Myend-
_Myfirst的区间;也就是说存在尚未使用的空间。

当push_back 的时候往往带有拷贝和析构多个操作,所以一下子分配比size()
大的空间capacity,可以减轻频繁操作造成的效率问题。

通常,向量缓存了一部分内存空间,用来容纳更多的元素,这样,下一次插入新元素的时候,就不必重新分配内存,提高了插入速度。

四、内存分配器Allocator

allocator 模板类:

#include 
template  class allocator
{
public:
    T *allocate(size_t);
    void deallocate(T *, size_t);
    void construct(T *, size_t);
    void destroy(T *);
    //.......
};

当然实际的接口没实现没那么简单,但大概实现的功能差不多:

allocate 调用operator new ;deallocate 调用 operator delete; construct
调用placement new (即在分配好的内存上调用拷贝构造函数),destroy
调用析构函数。

参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范

Primer
学习笔记_47_STL剖析(二):vector源码剖析、内存分配器Allocator
一、vector初始化源码
通过跟踪一个简单的程序,观察vector初始化的…

bzoj1218【HNOI2003】激光炸弹

使用MindFusion.Scheduling for
WPF将自定义实现资源视图的外观以达到更美观的演示。视图的外观自定义是通过设置Calendar.ResourceViewSettings对象的各种属性来达到的。我们将在银色主题上创建我们的演示,通过降低色彩的清晰度和对比度,使字体均匀的横跨整个视图。自定义过程分为以下步骤:

Description

一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。现在地图上有n(N<=10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。若目标位于爆破正方形的边上,该目标将不会被摧毁。
0

自定义的视图背景:

Input

输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示

1 calendar.ResourceViewSettings.CalendarStyle. Brushes.White;< /code>

Output

输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

自定义行标题:

Sample Input

2 1
0 0 1
1 1 1

1234567 calendar.ResourceViewSettings.ExpandableRows = false;calendar.ResourceViewSettings.HeaderStyle.FontFamily = headerFont;calendar.ResourceViewSettings.HeaderStyle.FontSize = 13;calendar.ResourceViewSettings.HeaderStyle.Foreground = newSolidColorBrush(Color.FromArgb(255, 64, 64, 64));calendar.ResourceViewSettings.HeaderStyle. Brushes.White;< /code>calendar.ResourceViewSettings.HeaderStyle.BorderBrush = borderBrush;calendar.ResourceViewSettings.HeaderStyle.BorderThickness = newThickness(0, 0, 0, 1);

发表评论