C++ 笔记:动态内存和智能指针

  • 对象的生存期:
    • 全局对象:程序启动时创建,程序结束时销毁
    • 局部自动对象:进入对象所在程序块时创建,离开程序块时销毁
    • static 对象:第一次使用时创建,程序结束时销毁
    • 动态分配的对象:创建之后只有在显式地被释放时才会销毁
      • 每个程序拥有一个内存池,称为自由空间或,用来存储动态分配的对象

智能指针

  • 传统的动态内存管理:
    • new:在动态内存中为对象分配空间,返回一个指向该对象的指针
    • delete:接受一个动态对象的指针,销毁该对象,释放内存
  • 智能指针:
    • #include <memory>
    • 智能指针是模板类,创建智能指针时需要提供具体的类型
    • shared_ptr:允许多个指针指向同一个对象
    • unique_ptr:“独占”所指向的对象
    • shared_ptrunique_ptr 都支持的操作
shared_ptr<T> sp_T;       // 空智能指针
unique_ptr<T> up_T;
*sp_T, *up_T              // 解引用
sp_T->mem, up_T->mem      // 成员访问
swap(p1, p2), p1.swap(p2) // 交换 p1 和 p2 

shared_ptr

shared_ptr<int> sp_int;
shared_ptr<vector<string> sp_str_vec;

shared_ptr 独有的操作

make_shared<T>(args)    // 返回一个 shared_ptr,指向一个动态分配的 T 类型对象,并使用 args 初始化该对象
shared_ptr<T>sp2(sp1)   // sp2 为 sp1 的拷贝;递增 sp1 指向的对象的计数器
sp2 = sp1               // 递减 sp2 原来所指向的对象的引用计数,递增 sp1 指向的对象的引用计数;
                        // 若 sp2 原来所指向的对象的引用计数变为 0,则释放该对象
sp.unique()             // 若 sp.use_count() 为 1,则返回 true,否则返回 false
sp.use_count()          // 返回与 sp 共享对象的智能指针数量
make_shared<T>(args)
  • 最安全的分配和使用动态内存的方法
  • 在内存中分配一个 T 类型的对象,使用 args 初始化该对象,并返回指向该对象的 shared_ptr
shared_ptr<int> sp_int = make_shared<int>(1024);
shared_ptr<string> sp_str = make_shared<string>("Hello, world!");
shared_ptr<vector<double>> sp_dbl_vec = make_shared<vector<double>>(vector<double>({3.14159, 1.414, 1.732}));
// 也可以使用 auto
list<int> int_lst{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto sp_int_lst = make_shared<list<int>>(int_lst);
shared_ptr 的赋值和拷贝
  • 进行赋值和拷贝时,每个 shared_ptr 都会记录指向相同对象的其他 shared_ptr 的数量
  • 每进行一次赋值和拷贝,shared_ptr 指向的对象的引用计数都会递增
  • 当给 shared_ptr 赋予一个新值,或是 shared_ptr 被销毁时,其原来所指向的对象的引用计数会递减
  • 当一个 shared_ptr 指向的对象的引用计数变为 0 时,便自动释放该对象
auto sp_int1 = make_shared<int>(1024);    // sp_int1 指向的对象只有 sp_int1 一个引用者
auto sp_int2 = sp_int1;                   // sp_int1 指向的对象有了两个引用者 sp_int1 和 sp_int2
使用 shared_ptr 实现多个对象之间共享数据
  • 一个对象的成员在对象销毁时也会被销毁;将数据保存在动态内存中,可以实现对象销毁时的数据保留
class StrBlob {
public:
  typedef vector<string>::size_type size_type;

  // constructors and destructor
  StrBlob();
  StrBlob(initializer_list<string> str_ilist);

  size_type size() const { return data->size(); }
  bool empty() const { return data->empty(); }
  
  void push_back(const string &str) { data->push_back(str); }
  void pop_back();

  string & front();
  string & back();

  shared_ptr<vector<string>> data;

private:
  void check(size_type i, const string & msg) const;
};

// 默认构造函数,在内存中分配一个空的 vector<string>
StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}

// 构造函数,在内存中分配所需的空间
StrBlob::StrBlob(initializer_list<string> str_ilist) : data(make_shared<vector<string>>(str_ilist)) {}

void StrBlob::check(size_type i, const string & msg) const {
  if (i >= data->size())
    throw out_of_range(msg);
}

string & StrBlob::front() {
  check(0, "front on empty StrBlob");
  return data->front();
}

string & StrBlob::back() {
  check(0, "front on empty StrBlob");
  return data->back();
}

void StrBlob::pop_back() {
  check(0, "pop_back on empty StrBlob");
  data->pop_back();
}


int main()
{
  StrBlob strblob1;

  {
    StrBlob strblob2({ "Hello, ", "welcome ", "to ", "the ", "C++ ", "world." });
    cout << strblob2.data << " : " << strblob2.front() << endl;   // output: 0328E30C : Hello,
    strblob1 = strblob2;
    cout << strblob1.data << " : " << strblob1.front() << endl;   // output: 0328E30C : Hello,
  }   // strblob2 被销毁,但 strblob2.data 原来指向的内存空间依然有效,并被 strblob1.data 所指

  cout << strblob1.data << " : " << strblob1.front() << endl;     // output: 0328E30C : Hello,

  cin.get();
  return 0;
}

unique_ptr

  • 一个 unique_ptr “独占”它所指向的内存,也就是说,在任一时刻,最多只能有一个 unique_ptr 指向一个给定对象
  • 当一个 unique_ptr 被销毁时,其所指的对象也被销毁

unique_ptr 独有的操作

unique_ptr<T> up1;        // 空指针,可以指向 T 类型的对象
unique_ptr<T, D> up2;     // up1 使用 delete 释放,up2 则使用类型为 D 的可调用对象释放
unique_ptr<T, D> up3(d);  // up3 使用类型为 D 的对象 d 释放

up = nullptr;             // 释放 up 指向的对象,并将 up 置空
up.release();             // up 放弃对指针的控制权,返回指针,并将 up 置空
up.reset();               // 释放 up 指向的对象
up.reset(q);              // 如果提供了内置指针 q,则令 up 指向这个对象;否则将 up 置空
up.reset(nullptr);
  • 定义一个 unique_ptr 时,需要将其绑定到一个 new 返回的指针
  • unique_ptr 不支持普通的赋值和拷贝操作
unique_ptr<double> up_dbl;
unique_ptr<int> up_int(new int(1024));
unique_ptr<string> up_str1(new string("Hello, world!"));
unique_ptr<vector<string>> up_str_vec(new vector<string>({ "Hello, ", "world!" }));

unique_ptr<string> up_str2(up_str1.release());  // 将所有权从 up_str1 转移给 up_str2,
                                                // release() 将 up_str1 置空
unique_ptr<string> up_str3(new string("Welcome to the C++ world."));
up_str2.reset(up_str3.release());               // 将所有权从 up_str3 转移给 up_str2,
                                                // 之后 reset() 将 up_str2 释放
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值