// @author: gr
// @date: 2014-10-20
// @email: [email protected]
使用new
对类类型和内置类型进行初始化会有不同的效果。对于类类型,不论采用何种形式,对象都会使用默认构造函数来初始化。直接初始化的内置类型对象值被良好定义,而默认初始化的对象的值是未定义的。
// 类型后没括号是默认初始化,有括号是直接初始化
string *ps1 = new string; //值初始为空string
string *ps2 = new string(); //值初始为空string
int *pi1 = new int; //值未定义
int *pi2 = new int(); //值初始为0
往往,对动态分配的对象进行直接初始化通常是个好主意。
可以使用auto
来自动推断我们想要分配的类型。要求,括号中仅有单一初始化器时才可以使用auto
。
// p指向一个与obj类型相同的对象,该对象用obj进行初始化
auto p1 = new auto(obj);
// 错误,括号中只能有一个初始化器
auto p2 = new auto{a, b, c};
p1的类型是一个指针,从obj自动推断出来。如果obj是一个int
,那么p1就是个int*
。
const
对象由于分配的对象是const
的,所以new
返回的指针是一个指向const
的指针。初始化规则和上面new
初始化一样,如果是内置类型,则需要显示初始化。
const int* pi = new const int(1024); //显示初始化
const string* ps = new const string; //隐示初始化
如果使用new
无法分配所要求的空间,这时会抛出一个bad_alloc
的异常。可以通过改变使用new
的方式来阻止抛出异常:
int* pi1 = new int(1); //如果分配失败,抛出std::bad_alloc异常
int* pi2 = new (nothrow) int(1); //如果分配失败,new返回一个空指针,不抛出异常
这种new
称为定位new
,允许向new
传递参数。在本例中,将nothrow
传递给new
。bad_alloc
和nothrow
都在头文件new
中,记着要#include <new>
。
delete
工作:
传递给delete
的指针必须指向动态分配的内存,或是一个空指针。不能对同一块内存释放两次。const
对象虽然是不可改变的,但是可以销毁的,和其他的销毁一样,如下:
const int* pi = new const int(1);
delete pi;
在delete指针过后,要重置为nullptr
。这样以后进行NULL
检查才会有作用。
delete p;
p = nullptr;
但即使这样,也不能保证所有指针都置为nullptr
。
int *p(new int(42));
auto q = p;
delete p;
p = nullptr;
虽然把p置为nullptr
,q仍为无效的。
shared_ptr
在头文件memory
中。使用它,记着#include <memory>
。
与vector
类似,智能指针也是模板,在尖括号内给出类型。智能指针使用方式与普通方式类似,解引用一个智能指针返回它指向的对象。
shared_ptr<string> p1;
p1->empty(); // 调用成员函数
shared_ptr<vector<string> > pv;
使用make_shared
函数,创建智能指针。
shared_ptr<int> p3 = make_shared<int>(42);
当指向一个对象的最后一个shared_ptr
被销毁时,即引用计数为0时,shared_ptr
类会自动销毁此对象。无需手动调用。
如果不初始化智能指针,它就会被初始化为一个空指针。还可以用new
返回的指针来初始化智能指针。只能使用显示转换,不能使用隐式转换:
shared_ptr<int> pi1 = new int(11); //错误,隐匿转换
shared_ptr<int> pi2(new int(11)); //正确,显示转换
与shared_ptr
不同,某个时刻只能有一个unique_ptr
指向一个给定对象。它不支持普通的拷贝或赋值操作。
unique_ptr<string> p1(new string("dfss"));
unique_ptr<string> p2(p1); //错误,不支持拷贝
unique_ptr<string> p3;
p3 = p1; //错误,不支持赋值
但可以通过调用release
或reset
将指针的所有权从一个unique_ptr
转移给另一个unique
:
// 将所有权从p1转移给p2
unique_ptr<string> p2(p1.release()); //release置为空
unique_ptr<string> p3(new string("Trex"));
// 将所有权从p3转移给p2
p2.reset(p3.release()); //reset释放了p2原来指向的内存
虽然标准库中auto_ptr
仍然存在,但使用它会有许多隐患,所以尽量不要使用。
weak_ptr
不控制所指向对象生存期的智能指针,它指向一个由shared_ptr
管理的对象。一旦最后一个指向对象的shared_ptr
被销毁,即使有weak_ptr
指向这个对象,对象也还是会被释放。这就是weak
的体现。
auto p = make_shared<int>(42);
weak_ptr<int> wp(p);
由于对象可能不存在,我们不能使用weak_ptr
直接访问对象,而必须调用lock
。此函数检查weak_ptr
是否仍存在,存在返回一个指向共享对象的shared_ptr。
if (shared_ptr<int> np = wp.lock()){ //如果np不为空则条件成立
// 在if中,np与p共享对象
}