// 静态内存(static) 局部static, 类static, 定义在任何函数之外的变量,由编译器自动创建和销毁,程序使用前创建,程序结束时销毁,
// 栈(stack) 函数内的非static 对象,由编译器自动创建和销毁,仅在其定义的程序块运行时存在
// 堆(heap) 动态分配的对象,运行时分配的对象,程序显式的销毁
// 动态内存的管理
// new 在动态内存中为对象分配空间并返回指向该对象的指针,可选择进行初始化
// delete 接受动态对象的指针,销毁该对象,释放与之关联的空间
#include<memory>
#include<iostream>
#include<string>
#include<initializer_list>
#include<vector>
#include<stdexcept>
#include<new>
using std::shared_ptr;
using std::unique_ptr;
using std::make_shared;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::initializer_list;
using std::vector;
using std::out_of_range;
using std::nothrow;
// 对象间共享数据类定义
class StrBlob{
public:
typedef vector< string>::size_type size_type;
// 构造函数
StrBlob();
StrBlob( initializer_list< string> il);
// 普通成员函数
size_type size() const {
return data->size();
}
size_type count() const {
return data.use_count();
}
bool empty() const {
return data->empty();
}
// 添加删除
void push_back( const string &s){
data->push_back( s);
}
void pop_back();
// 访问
string& front() const;
string& back() const;
private:
// 数据
shared_ptr< vector< string>> data;
// 检查 data[i] 的合法,抛出异常
void check( size_type i, const string &s) const;
};
// 构造函数
StrBlob::StrBlob() : data( make_shared< vector< string>>()){}
StrBlob::StrBlob( initializer_list< string> il) :
data( make_shared< vector< string>>( il)){}
// 检查 data[i] 的合法,抛出异常
void StrBlob::check( size_type i, const string &s) const{
if( i >= data->size())
throw out_of_range( s);
}
// 删除
void StrBlob::pop_back(){
check(0, "pop_back on empty strBlob");
data->pop_back();
}
// 访问
string& StrBlob::front() const {
check(0, "front on empty strBlob");
data->front();
}
string& StrBlob::back() const {
check(0, "back on empty strBlob");
data->back();
}
// 返回动态内存
vector< int> *get_pvi(){
return new vector< int>();
}
void save_pvi(vector< int> * pvi){
int n = 0;
while( cin >> n)
pvi->push_back( n);
}
void print_pvi(vector< int> * pvi){
for( auto &w : *pvi)
cout << w << endl;
}
int main(){
// 智能指针(smart pointer),定义于 memory.h
// shared_ptr 允许多个指针指向同一个对象
// unique_ptr 独占所指向的对象
// week_ptr 弱引用,指向 shared_ptr 所管理的对象
// shared_ptr unique_ptr 都支持的操作
// 1.创建时必须指明一个指针可以指向的类型,默认初始化为空指针
shared_ptr< string> sp1, sp2;
unique_ptr< string> up;
// 2.用作判断条件,若指向一个对象,则为 true
if( sp1 && sp1->empty()){ //4.调用指向对象的成员
// 3.解引用,获得指向对象的左值
*sp1 = "hello";
// 6.返回智能指针中保存的指针
cout << *( sp1.get()) << endl;
}
// 5.交换两个指针
swap( sp1, sp2);
sp1.swap( sp2);
// shared_ptr 独有的操作
// 1> make_shared 返回一个 shared_ptr,指向一个动态分配的类型为 string的对象,并初始化为 world
// 最安全的分配和使用动态内存的方法,初始化的参数必须是指定类型的构造函数的参数
sp2 = make_shared< string>( "world");
// 每个shared_ptr 都有一个引用计数(reference count),当拷贝时,计数器增加,赋值或销毁时,计数器减少,当变为0时,自动释放所管理的对象
// 2> sp3是 sp2 一个拷贝,同时增加 sp2的计数器,sp2 的指针必须能转换为 string *
shared_ptr< string> sp3( sp2);
// 3> sp1 和 sp3 所保存的指针必须能够相互转换,同时递减sp1计数,若为0,则释放其管理的内存,递增 sp3 的计数
sp1 = sp3;
// 4> 如果 use_count() 为1, 则unique() 为true,否则为 false
if( sp3.unique())
cout << "count == 1" << endl;
else
// use_count() 返回与 sp3 共享对象的智能指针数量,比较慢,主要用于测试
cout << "count : " << sp3.use_count() << endl;
// 使用动态内存的情况
// 不知道要使用多少对象
// 不知道对象的确切类型
// 在多个对象之间共享数据
StrBlob sb1, sb2{"hello", "world"};
cout << "sb1.count = " << sb1.size() << endl;
cout << "sb2.count = " << sb2.size() << endl;
{
StrBlob sb3{"test"};
sb1 = sb3;
cout << "sb3.count = " << sb3.size() << endl;
cout << "sb1.count = " << sb1.size() << endl;
sb3.push_back( "strblob");
cout << "sb3.count = " << sb3.size() << endl;
cout << "sb1.count = " << sb1.size() << endl;
}
const StrBlob sb4{ "say", "yeah!~"};
cout << sb4.front() << " < > " << sb4.back() << endl;
cout << sb2.front() << " < > " << sb2.back() << endl;
cout << "sb1.count = " << sb1.size() << endl;
cout << "sb2.count = " << sb2.size() << endl;
sb1 = sb2;
cout << "sb1.count = " << sb1.size() << endl;
cout << "sb2.count = " << sb2.size() << endl;
// 直接管理内存 new 分配内存,delete 释放 new 分配的内存
// 注意区别
int *pi1 = new int; // 默认初始化,对于内置类型,其值是未定义的
int *pi2 = new int(); // 值初始化
auto *pi3 = new auto(5); // 自动推断类型
const int *pi4 = new const int(1024); // const 对象必须初始化,如果类类型有默认构造函数可以隐式初始化
cout << *pi1 << " - " << *pi2 << " - " << *pi3 << " - " << *pi4 << endl;
// 如果内存耗尽,new 表达式失败,会抛出 bad_alloc 异常
// bad_alloc nothrow new 定义于 new.h
int *pi5 = new (nothrow) int(); // 定位 new (placement new),如果分配失败,不会抛出异常,返回一个空指针
// 释放动态内存 (delete expression)
// 释放一块并非 new 分配的内存或将相同的指针释放多次,其行为是未定义的
delete pi5; // 两步,销毁指向的对象,释放对应内存,pi5必须是指向动态分配的内存或是一个空指针
// 动态内存有效期直到显式释放
// 如果使用了返回动态内存指针的函数,使用者使用完必须显式释放
// 常见问题:
// 1.忘记 delete 分配的内存,很难检测,多数情况下,等内存耗尽才发现
// 2.使用已经释放掉的对象,虽然指针已失效但多数情况下仍保存了原地址,类似于未定义的指针,建议置为空指针,
// 但是如果有多个指针指向该内存,逐个释放也很麻烦
// 3.释放已经释放过的内存,未定义行为
auto pvi = get_pvi();
save_pvi( pvi);
print_pvi( pvi);
delete pvi;
// 智能指针的构造函数是 explicit, 不能进行隐式转换,只能使用直接初始化
// 错误:shared_ptr< string> ps1 = new string("hello world");
shared_ptr< string> ps2( new string("hello world"));
// 定义改变 shared_ptr 的其他方法
// shared_ptr< T> p( q) p 管理 q指向的对象,q必须指向 new 分配的内存,且能够转换为 T* 类型
// shared_ptr< T> p( u) p 从 unique_ptr u 那里接管了对象的所有权,将 u 置空
// shared_ptr< T> p( q, d) p 从 内置类型指针 q 那里接管了对象的所有权,q 必须能转换为 T*, p 将使用可调用对象 d 代替 delete
// shared_ptr< T> p( p2, d) p 是 shared_ptr p2 的拷贝, 但 p 可以使用可调用对象 d 代替 delete
// p.reset() 若 p 是唯一指向其对象的 shared_ptr,reset会释放此对象
// p.reset( q) 若同时传递了可选的内置指针 q,会另 p 指向 q, 否则为空
// p.reset( q, d) 若同时还传递了 d,使用可调用对象 d 代替 delete
// 不要使用 get() 初始化另一个智能指针或为智能指针赋值
shared_ptr< int> spi1( new int( 99));
// pi1 和 spi1 指向同一个内存
int *pi1 = spi1.get();
{
// pi1 spi2 和 spi1 指向同一个内存,但分别是2个不同的智能指针,且计数都为1,当spi2 脱离作用域,其指向的内存会被释放,后续的解引用行为未定义
shared_ptr< int> ( spi2);
}
int vspi1 = *spi1; //未定义行为
// 智能指针使用规范:
// 不使用相同的内置指针初始化多个智能指针
// 不 delete get() 返回的指针
// 不使用 get() 初始化或reset 另一个智能指针
// 如果使用了 get() 指针,当其最后一个对应的智能指针销毁后,指针变为无效
// 如果使用的智能指针管理的资源不是 new 分配的内存,记住传递一个删除器
// unique_ptr
// 定义改变 unique_ptr 的其他方法
// unique_ptr< T> p 指向 T 类型的对象, 空 unique_ptr, 可以使用 delete 释放
// unique_ptr< T, D> p 同上,使用 D 类型的可调用对象来释放指针
// unique_ptr< T, D> p ( d) 同上,使用 D 类型的可调用对象 d来释放指针
// p = nullptr 释放 p 指向的对象,将 p 置空
// p.release() 放弃控制权,返回指针,将 p 置空
// p.reset() 释放此对象
// p.reset( q) 若同时传递了可选的内置指针 q,会另 p 指向 q, 否则为空
// p.reset( nullptr)
// 不支持赋值和拷贝, 可以通过 release() 或 reset() 转移控制权
unique< int> upi1;
unique< int> upi2 ( new int ( 99));
upi1.reset( upi2.release());
// weak_ptr
// 指向 shared_ptr 关联的对象,但不增加其引用计数,当对象最后一个 shared_ptr 被销毁,即使有 weak_ptr 仍会销毁
// weak_ptr< T> w 空 weak_ptr 指向类型 T 的对象
// weak_ptr< T> w( sp) 与 shared_ptr sp 指向同一个对象, T 必须能转换为 sp 指向的类型
// w = p p 可以是 shared_ptr 或 weak_ptr,赋值后共享对象
// w.reset() 置空 w
// w.use_count() 与 w 共享对象的 shared_ptr 数量
// w.expired() 若 w.use_count() 为0,返回 true,否则为 false
// w.lock() 如果 w.expired() 为真,返回空 shared_ptr, 否则返回指向 w 对象的 shared_ptr
return 1;
}
c++ primer(第五版)笔记 第十二章 动态内存(1)
最新推荐文章于 2021-08-03 13:18:11 发布