静态内存及栈
- 静态内存:局部static、类static数据成员、定义在任何函数之外的变量
- 栈:定义在函数之内的非static对象
分配在静态内存中的对象由编译器自动创建和销毁。栈对象在其定义的程序块运行时存在。static对象在使用前分配,程序结束时销毁。
智能指针
- s h a r e d _ p t r shared\_p tr shared_ptr : 允许多个指针指向同一个对象;
- u n i q u e _ p t r unique\_ptr unique_ptr : 独占所指向的对象;
- w e a k _ p t r weak\_ptr weak_ptr : 弱引用,指向 s h a r e d _ p t r shared\_ptr shared_ptr所管理的对象。
s h a r e d _ p t r shared\_ptr shared_ptr
shared_ptr<string> p1;
shared_ptr<list<int> > p2;
p1 = make_shared<string>(11, '1');// 11 个1的字符串
cout << *p1 << endl;
auto p3 = make_shared<int>();//默认0
cout << *p3 << endl;
拷贝和赋值
当指向一个对象的最后一个
s
h
a
r
e
d
_
p
t
r
shared\_ptr
shared_ptr被销毁时,
s
h
a
r
e
d
_
p
t
r
shared\_ptr
shared_ptr类会通过析构函数自动销毁此对象,并释放内存。
class Node {
public:
int a;
Node() {
a = 1;
};
~Node() {
cout << "********" << endl;
}
};
int main() {
auto pp = make_shared<Node>();
cout << pp->a << endl;
pp = NULL;
cout << "2222222" << endl;
return 0;
}
/*
输出:
1
********
2222222
*/
直接管理内存
如果提供一个括号包围的初始化器,那么可以用auto来推断想要分配的对象的类型,但是初始化器只能有一个。
auto p1 = new auto(obj);// 正确
auto p2 = new auto{a,b,c};//错误
动态分配的
c
o
n
s
t
const
const对象
一个动态分配的const对象必须进行初始化。
const int *p1 = new const int(1024);
const string *p2 = new const string;
delete p1;
delete p2;
new 返回的是一个指向const的指针。
内存耗尽
内存耗尽的时候会抛出
b
a
d
_
a
l
l
o
c
bad\_alloc
bad_alloc 异常。但也可以阻止
int *p1 = new (nothrow) int;//若分配失败,则返回空指针
s h a r e d _ p t r shared\_ptr shared_ptr和 n e w new new结合使用
我们不能将一个内置指针隐式的转化为一个智能指针。
shared_ptr<int> p1(new int(2024));
shared_ptr<int> clone(int p){
return shared_ptr<int>(new int(p));
}
不要混合使用普通指针和智能指针
不要使用
g
e
t
get
get初始化另一个智能指针或者赋值
其他
s
h
a
r
e
d
_
p
t
r
shared\_ptr
shared_ptr操作
p = new int(1024);//错误
p.reset(new int(1024));//正确
reset会更新引用计数,必要时会释放对象。reset可以和unique一起使用来管理多个shared_ptr共享的对象。
if( !p.unique() )
p.reset(new string(*p));//不是唯一用户,分配新的拷贝
*p += newVal;//现在是唯一用户,可以更改对象的值
智能指针和异常
使用自己的释放操作 d e l e t e delete delete
class Node {
public:
int a;
Node() {
a = 1;
}
Node(int x) : a(x){}
~Node() {
cout << "********" << endl;
}
};
void endf(Node *x) {
cout << x->a << endl;
}
int main() {
shared_ptr<Node> p1(new Node(200),endf);
cout << p1->a << endl;
return 0;
}
/*
输出:
200
200
*/
class Node {
public:
int a;
Node() {
a = 1;
}
Node(int x) : a(x){}
//~Node() {
// cout << "********" << endl;
//}
};
void endf(Node *x) {
cout << x->a << endl;
}
int main() {
//shared_ptr<Node> p1(new Node(200),endf);
shared_ptr<Node> p1(new Node(200));
cout << p1->a << endl;
return 0;
}
/*
输出:
200
*/
u n i q u e _ p t r unique\_ptr unique_ptr
一个
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr拥有它所指向的对象。
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr不支持普通的拷贝或者赋值操作。
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr的一些操作:
虽然不能赋值或者拷贝,但是可以使用
r
e
s
e
t
reset
reset和
r
e
l
e
a
s
e
release
release来转移指针的所有权。
unique_ptr<string> p2(p1.release());
unique_ptr<string> p3(new string("123"));
p2.reset(p3.release());
r e l e a s e release release会切断 u n i q u e _ p t r unique\_ptr unique_ptr与之前管理的内存之间的联系,但是不会释放资源,所以需要负责释放资源
p2.release();//错误 丢失了指针
auto p = p2.release();//必须记得delete(p)
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr 不能拷贝的规则有一个例外:可以拷贝或者赋值一个将被销毁的
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr对象。
a
u
t
o
p
t
r
auto_ptr
autoptr
向
u
n
i
q
u
e
_
p
t
r
unique\_ptr
unique_ptr传递删除器
class Node {
public:
int a;
Node() {
a = 1;
}
Node(int x) : a(x){}
~Node() {
cout << "********" << endl;
}
};
void endf(Node *x) {
cout << x->a << endl;
}
int main() {
//shared_ptr<Node> p1(new Node(200),endf);
//shared_ptr<Node> p1(new Node(200));
unique_ptr<Node,decltype(endf)*> p1(new Node(200), endf);
cout << p1->a << endl;
return 0;
}
/*
输出:
200
200
*/
class Node {
public:
int a;
Node() {
a = 1;
}
Node(int x) : a(x){}
~Node() {
cout << "********" << endl;
}
};
void endf(Node *x) {
cout << x->a << endl;
}
int main() {
//shared_ptr<Node> p1(new Node(200),endf);
//shared_ptr<Node> p1(new Node(200));
//unique_ptr<Node,decltype(endf)*> p1(new Node(200), endf);
unique_ptr<Node> p1(new Node(200));
cout << p1->a << endl;
return 0;
}
/*
输出:
200
********
*/
w e a k _ p t r weak\_ptr weak_ptr
w
e
a
k
_
p
t
r
weak\_ptr
weak_ptr指向一个
s
h
a
r
e
d
_
p
t
r
shared\_ptr
shared_ptr管理的对象,但是并不会改变其引用计数。
w
e
a
k
_
p
t
r
weak\_ptr
weak_ptr的一些操作:
使用
w
e
a
k
_
p
t
r
weak\_ptr
weak_ptr时,不能直接访问对象,必须要用
l
o
c
k
lock
lock。
auto p = make_shared<int>(100);
weak_ptr<int> wp(p);
if( shared_ptr<int> np = wp.lock() ){
//---
}
一个问题:
有一个现成的约定是当我们将一个原生指针交给(具有资源所有权的)智能指针的时候,这个智能指针被允许认为自己暂时获得了这个原生指针指向资源的独占所有权。对于std::shared_ptr,分享所有权虽然是其功能之一,但如果它即将指向的资源所有权已经有人占据了,你必须让它知道资源已经被谁占了。举例:
int* p = new int();
std::shared_ptr<int> sp1(p); //sp1认为自己独占了p指向的资源。
std::shared_ptr<int> sp2(sp1); //sp2初始化自一个智能指针而非原
//生指针,其与sp1达成共识,共享
//了p指向的资源
std::shared_ptr<int> sp3(p); //sp3认为自己独占了p指向的资源,
//但sp1和sp2还没答应共享给它
//作用域结束时,sp1、sp2和sp3指向的是同一资源,应当只销毁一次;但
//sp1和sp2不知道sp3宣称占了资源,sp3也不知道sp1和sp2宣称占了资源,
//结果该资源就会被销毁两次。多次销毁同一个资源是未定义行为。