Vector Changing size
ordinary reserve()
void vector::reserve(int newalloc)
{
if (newalloc<=space) return; // never decrease allocation
double* p = new double[newalloc]; // allocate new space
for (int i=0; i
ordinary resize()
void vector::resize(int newsize)
// make the vector have newsize elements
// initialize each new element with the default value 0.0
{
reserve(newsize);
for (int i=sz; i
ordinary push_back()
void vector::push_back(double d)
// increase vector size by one; initialize the new element with d
{
if (space==0)
reserve(8); // start with space for 8 elements
else if (sz==space)
reserve(2*space); // get more space
elem[sz] = d; // add d at end
++sz; // increase the size (sz is the number of elements)
}
allocator
deallocate()是将分配出的空间(没有被使用的空间) 放回主存。destroy()是将已经被构造的空间(已有值) 析构成没有被使用的空间放回内存池[2]
template class allocator {
public:
// . . .
T* allocate(int n); // allocate space for n objects of type T
void deallocate(T* p, int n); // deallocate n objects of type T starting at p
void construct(T* p, const T& v); // construct a T with the value v in p
void destroy(T* p); // destroy the T in p
};
vector
template> class vector {
A alloc; // use allocate to handle memory for elements
// . . .
};
vector::reserve()
template void vector::reserve(int newalloc)
{
if (newalloc<=space) return; // never decrease allocation
T* p = alloc.allocate(newalloc); // allocate new space
for (int i=0; i
vector::resize()
template
void vector::resize(int newsize, T val = T())
{
reserve(newsize);
for (int i=sz; i
vector::push_back()
template
void vector::push_back(const T& val)
{
if (space==0) reserve(8); // start with space for 8 elements
else if (sz==space) reserve(2*space); // get more space
alloc.construct(&elem[sz],val); // add val at end
++sz; // increase the size
}
make_vec()
try catch
vector* make_vec() // make a filled vector
{
vector* p = new vector; // we allocate on free store
try {
// fill the vector with data; this may throw an exception
return p;
}
catch (. . .) {
delete p; // do our local cleanup
throw; // re-throw to allow our caller to deal with the fact
// that make_vec() couldn’t do what was
// required of it
}
}
unique_ptr vector*
vector* make_vec() // make a filled vector
{
unique_ptr> p {new vector}; // allocate on free store
// . . . fill the vector with data; this may throw an exception . . .
return p.release(); // return the pointer held by p
}
unique_ptr unique_ptr
unique_ptr> make_vec() // make a filled vector
{
unique_ptr> p {new vector}; // allocate on free store
// . . . fill the vector with data; this may throw an exception . . .
return p;
}
A
unique_ptr
is very much like an ordinary pointer, but it has one significant restriction: you cannot assign oneunique_ptr
to another to get twounique_ptrs
to the same object.[1]
pLarge ->
DoSomething();
智能指针是在
标头文件中的 std
命名空间中定义的,对 RAII (获取资源即初始化”编程惯用法)至关重要:
RAII
主要目的是确保资源获取与对象初始化 同时发生 ;
RAII
主要原则是为将任何堆分配资源(例如,动态分配内存或系统对象句柄)的所有权提供给其析构函数包含用于删除或释放资源的代码以及任何相关清理代码的堆栈分配对象;
通过使用熟悉的指针运算符(-> 和 *)访问封装指针,智能指针类将重载这些运算符以返回封装的原始指针[5]
#include
#include
using namespace std;
class MyClass {
public:
MyClass() { cout << "MyClass()\n";}
void say_hello() {cout << "Hello!\n";}
~MyClass() { cout << "~MyClass()\n";}
};
int main()
{
unique_ptr p_new;
p_new->say_hello();
MyClass* p_old;
p_old->say_hello();
}
Hello!
Hello!
Return by moving
vector make_vec() // make a filled vector
{
vector res;
// . . . fill the vector with data; this may throw an exception . . .
return res; // the move constructor efficiently transfers ownership
}
move
class vector {
int sz;
double* elem;
public:
vector(vector&& a); // move constructor
vector& operator=(vector&&); // move assignment
// . . .
};
move constructor
vector::vector(vector&& a)
:sz{a.sz}, elem{a.elem} // copy a’s elem and sz
{
a.sz = 0; // make a the empty vector
a.elem = nullptr;
}
move assignment
vector& vector::operator=(vector&& a) // move a to this vector
{
delete[] elem; // deallocate old space
elem = a.elem; // copy a’s elem and sz
sz = a.sz;
a.elem = nullptr; // make a the empty vector
a.sz = 0;
return *this; // return a self-reference
}
RAII
This technique is usually referred to by the awkward phrase Resource Acquisition Is Initialization abbreviated to RAII.
vector::reserve
template
void vector::reserve(int newalloc)
{
if (newalloc<=space) return; // never decrease allocation
T* p = alloc.allocate(newalloc); // allocate new space
for (int i=0; i
RAII for vector
vector_base
template
struct vector_base {
A alloc; // allocator
T* elem; // start of allocation
int sz; // number of elements
int space; // amount of allocated space
vector_base(const A& a, int n)
: alloc{a}, elem{alloc.allocate(n)}, sz{n}, space{n}{ }
~vector_base() { alloc.deallocate(elem,space); }
};
vector : vector_base
template>
class vector : private vector_base {
public:
// . . .
};
rewrite reserve()
template
void vector::reserve(int newalloc)
{
if (newalloc<=this–>space) return; // never decrease allocation
vector_base b(this–>alloc,newalloc); // allocate new space
uninitialized_copy(b.elem,&b.elem[this–>sz],this–>elem); // copy
for (int i=0; isz; ++i)
this–>alloc.destroy(&this–>elem[i]); // destroy old
swap>(*this,b); // swap representations
}
Similarly, we have to explicitly use
this–>
when we refer to a member of the base classvector_base
from a member of the derived classvector
, such asvector
.::reserve()
对比看oridinary 的reserve()和 RAII 的reserve()
deallocate()
被放到了析构函数之中
vector::reserve
alloc.deallocate(elem,space); // deallocate old space
struct vector_base
~vector_base() { alloc.deallocate(elem,space); }
allocate()
被放到了构造函数之中
vector::reserve
T* p = alloc.allocate(newalloc);
template void vector::reserve
vector_base b(this–>alloc,newalloc);
struct vector_base
T* elem; // start of allocation
vector_base(const A& a, int n)
: ... elem{alloc.allocate(n)}...{}
/* 可以看到新版本b.elem相当于原始版本的p */
复制操作的实现
for (int i=0; isz],this–>elem); // copy
/*
b 是初始化的新的对象;
b.elem相当于原始版本的p;
uninitialized_copy(...)是STL函数;
*/
销毁已经被赋值的东西
for (int i=0; isz; ++i)
this–>alloc.destroy(&this–>elem[i]); // destroy old
/*
除了显式地写出来this-> 并没有什么区别
*/
指向新分配的空间
elem = p;
space = newalloc;
swap>(*this,b); // swap representations
vector_base(const A& a, int n)
: ... space{n}{ }
/*
space = newoalloc 的赋值操作早在在构造函数中初始化成员变量时已经完成
*/
reference
[1].Programming -- Principles and Practice Using C++ (Second Edition) http://www.stroustrup.com/Programming/
[2]. 有关allocator类的destroy和deallocate [A_LeiQ] 于 2017.04.09 15:24 提问
http://ask.csdn.net/questions/377223
[3]. 如何:创建和使用 unique_ptr 实例
https://msdn.microsoft.com/zh-cn/library/hh279676.aspx
[4].std::unique_ptr
http://zh.cppreference.com/w/cpp/memory/unique_ptr
[5] 智能指针 现代C++
https://msdn.microsoft.com/zh-cn/library/hh279674.aspx
note
- 对比三个函数的2种情况,比如:
ordinary reserve()
以及reserve()
,就可以看到allocator
的用法; -
allocator
中destory()
销毁的是已经被赋过值了的那些东西,和deallocate()
是不一样的; - 指针哪里什么时候可以用
-> *
,智能指针unique_ptr
就可以; - RAII是一种编程技术,创造条件使得可以用构造函数和析构函数从而达到防止资源泄漏的目的;