动态内存:之前的程序使用对象有着严格定义的生存期,会自动销毁。C++支持动态分配对象,动态分配对象的生存期和他们在哪里创建是无关的,只有当显式的被释放,这些对象才会销毁。
标准库定义了智能指针对象可以自动释放内存。
new在动态内存中分配空间并且返回一个指向该对象的指针,delete接受一个动态对象的指针销毁该对象并释放相关的内存
使用动态内存的原因:
1.程序不知需要多少对象2.程序不知道对象类型3.程序需要在多个对象之间共享数据————允许多个对象共享相同状态

忘记释放内存会导致内存泄漏,释放了被指针指向的内存会导致非法指针。
标准库定义的智能指针可以自动释放指向的对象,share_ptr允许多个指针指向同一个对象,unique_ptr独占所指向的对象。
share_ptr类
默认初始化的智能指针保存一个空指针。
智能指针可以解引用。
shared_ptr独有操作:make_shared<T>(args) 返回一个ptr指向一个动态分配的类型为T的对象,用args初始化
shared_ptr<T>p(q) p 是shared_ptr q的拷贝此操作会递增q里的计数器
p.unqiue() 返回引用计数是否为1
p.use_count() 速度慢,返回和p共享对象的智能指针数目

make_shared 函数
最安全的分配和使用动态内存的方法是调用一个make_shared的函数,此函数在动态内存中分配一个对象并且初始化,返回指向这个对象的shared_ptr,和智能指针一样,包含在memory中

shared_ptr<int> p = make_shared<int>(42);
类似emplace 用参数来构造给定类型的对象,传递的参数必须和<T>的某个构造函数相匹配,然后进行值初始化

shared_ptr 的拷贝和赋值
当进行拷贝或者赋值操作每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象,可以认为每个shared_ptr都有一个关联的计数器,通常称为引用计数,无论何时我们copy一个shared_ptr,计数器将会递增,如:用一个s_ptr初始化另外一个s_ptr,或者把它作为一个参数传递给一个函数 ,或者把它作为函数的返回值,他的关联计数器就会增加。
而当我们给s_ptr赋予一个新的值或者,离开作用域,计数器就会减少。
一旦s_ptr计数器变为0,它就会自动释放自己管理的对象。(调用该对象的析构函数)

s_ptr在无用之后仍然保存的一种情况:将它放在一个容器中随后重排了容器。

定义STRBLOB类
定义一个管理string 的类,实现我们所希望的数据共享。
将一个vector保存在一个类定义对象中,为了避免它在离开作用域时被销毁,将其保存在动态内存中。
用make_shared 和shared_ptr 来构造类对象

直接管理内存:new delete
new 返回一个指向该对象的指针,对象可以采用传统构造方式也可以使用列表初始化。
用new分配const 对象 是合法的! 一个动态分配的const对象必须初始化!
当内存耗尽 new表达式就会失败,抛出一个bad_alloc 的一场,我们可以改变使用new的方式来阻止它抛出异常:
int *p2 = new (nothrow) int;如果分配失败返回一个空指针

释放动态内存 delete 将内存归还给系统
动态对象生存期直到被释放为止

delete之后重置指针:在delete一个动态对象之后,指针就变成了空悬指针,有一种方法可以避免该问题,在将要离开作用于之前释放关联的内存。或者给他赋值null

shared_ptr 和new 结合使用
可以使用new返回的指针来初始化智能指针.接受指针参数的智能指针构造函数是explicit 的,所以不能将一个内置指针隐式转换为一个只能指针,必须直接初始化形式
shared_ptr<int> p2(new int(1024));
p1的初始化隐式地要求编译器用一个new返回的int*来创建一个shared_ptr ,由于我们不能进行内置指针到智能指针的隐式转换,必须直接初始化.必须将shared_ptr显式绑定到一个想要返回的指针上.
返回语句中那个不能隐式转换一个内置普通指针!
必须shared_ptr<int> clone(int p)
{
return shared_ptr<int>(new int(p));
}
在默认情况下一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete来销毁构建他的对象.

不要混合使用智能指针和普通指针:使用一个内置指针来访问一个智能指针负责的对象是很危险的,因为我们无法知道对象何时会被销毁。
shared_ptr可以协调对象的析构,但是仅仅是自身的copy之间.
如果将一个内置指针初始化的shared_ptr作为参数传入,会导致错误的释放空间。

不要使用get初始化另一个智能指针或者为智能指针赋值
get用来将指针的访问权限传递.int *q = p.get();在使用q的时候要注意不能释放!
p.get()获得一个普通指针

如果执行以下代码会发生什么?
auto sp = make_shared<int>();
auto p = sp.get();
delete p;
sp的引用计数仍然为1,但是它指向的int对象已经被释放了

unique_ptr
和shared_ptr初始化的形式相同,必须直接初始化。

weak_ptr 是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,绑定到shared_ptr不会改变其引用计数,一旦最后一个只想对象的shared_ptr被销毁那么对象会被释放
调用lock()函数检查对象是否已经被释放
通过使用weakptr不会影响shared_ptr指向的对象的生存期,但是可以阻止用户访问一个不再存在的vector的企图.

动态数组
依次分配多个内存空间,new,allocator。大多数应用应该直接使用标准容器。new和数组:在类型名之后加一对方括号,在其中指明要分配的对象的数目.new分配多个数据,返回一个指向第一个数据的指针。
动态数组并不是数组类型! 得到了一个数组元素类型的指针。
初始化动态分配对象的数组
string *psa = new string[10]();10个空string
动态分配一个空数组是合法的:
可以用任意表达式来确定要分配的对象数目:
size_t n = getsize();int *p = new int[n];当我们用new分配一个大小为0的数组,new返回一个合法的非空指针!(对于零长度来说,这个指针和尾后指针一样) ,可以像使用为后迭代器一样使用。
释放动态数组
delete [] p;释放p指向的数组中的元素,逆序销毁。

allocator 类
new有一些灵活性上的局限,其中一方面表现在它将内存分配和对象构造组合在了一起,delete将对象析构和内存释放组合在了一起,造成不必要的浪费,我们分配单个对象时希望把内存分配和对象初始化组合在一起。因为在这种情况下我们几乎可以肯定对象的值。

当分配一大块内存时,我们通常计划在这块内存上按需构造对象,再次情况下,我们希望将内存分配和对象构造分离,这意味着可以分配大块内存,但只在真正需要的时候执行对象创建操作。

allocator分配的内存是未构造的,我们按需要在次内存中构造对象。construct 函数接受一个指针和零个或者多个额外函数在给定位置构造一个元素,额外参数用来初始化构造对象。

当我们用完对象之后,对每个构造的函数调用destroy来销毁。使用allocate的内存必须用construct构建对象,使用未构造的内存行为是未定义的。
使用标准库:
文本查询程序—— 在一个给定的文本里面查询单词:输出结果出现的次数和所在行的列表,如果一个单词在一行中出现多次那么只列出一次

C++ primer chapter 12的更多相关文章

  1. 零元学Expression Blend 4 - Chapter 12 用实例了解布局容器系列-「Viewbox」

    原文:零元学Expression Blend 4 - Chapter 12 用实例了解布局容器系列-「Viewbox」 本系列将教大家以实做案例认识Blend 4 的布局容器,此章介绍的布局容器是Bl ...

  2. Think Python - Chapter 12 Tuples

    12.1 Tuples are immutable(元组是不可变的)A tuple is a sequence of values. The values can be any type, and t ...

  3. C++ Primer Chapter 1

    When I start reviewing, I thought Chapter is useless. Because the title is "Getting Start" ...

  4. 《Java 8 in Action》Chapter 12:新的日期和时间API

    在Java 1.0中,对日期和时间的支持只能依赖java.util.Date类.同时这个类还有两个很大的缺点:年份的起始选择是1900年,月份的起始从0开始. 在Java 1.1中,Date类中的很多 ...

  5. Chapter 12 IP Weighting and Marginal Structural Model

    目录 12.1 The causal question 12.2 Estimating IP weights via modeling 12.3 Stabilized IP weights 12.4 ...

  6. C++primer 练习12.27

    // 12_27.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...

  7. C++primer 练习12.6

    编写函数,返回一个动态分配的int的vector.将此vector传递给另一个函数,这个函数读取标准输入,将读入的值 保存在vector元素中.再将vector传递给另一个函数,打印读入的值.记得在恰 ...

  8. Chapter 12 外观模式

    外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个模式使得这一子系统更加容易使用. 外观模式三个阶段: 首先,在设计初期阶段,应该要有意识的将不同的两个层分离. 其次,在 ...

  9. C++ primer 练习 12.7

    重做上一题,这次使用shared_ptr 而不是内置指针.上一题题目为:(编写函数,返回一个动态分配的int的vector.将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在ve ...

随机推荐

  1. 什么是JavaScript的转义字符?譬如\n有什么作用?

    在JavaScript字符串中,反斜线(\)有着特殊的用途,反斜线后加一个字符,就不再表示它们的字面义了,比如\n就是一个转义字符(escape sequence),它表示的是一个换行符.在表格3-1 ...

  2. Java高质量20问

    问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你在一个线程里初始化了一个 ...

  3. ORA-01075: you are currently logged on

    [root@hear01 ~]# su - oracle[oracle@hear01 ~]$ sqlplus "/as sysdba" SQL*Plus: Release 11.2 ...

  4. setjmp和longjmp函数

    关于setjmp函数和longjmp函数有话要说,是UNIX高级环境变成看到了10.10信号那章用到了,研究一下,这里作为补充. setjmp(jmp_buf env_buf) 函数可以将当前的运行环 ...

  5. 【Leetcode】115. Distinct Subsequences

    Description: Given two string S and T, you need to count the number of T's subsequences appeared in ...

  6. mysql视图的操作

    一.创建视图的语法形式 CREATE VIEW view_name AS 查询语句 ; 使用视图 SELECT * FROM view_name ; 二.创建各种视图 1.封装实现查询常量语句的视图, ...

  7. [ SHOI 2012 ] 随机树

    \(\\\) \(Description\) 开始有一棵只有一个根节点的树.每次随机选择一个叶子节点,为他添上左右子节点,求: 生成一棵有\(N\)个叶节点的树,所有叶节点平均高度的期望. 生成一棵有 ...

  8. 《Java编程的逻辑》第三部分 泛型与容器

  9. 利用php生成验证码

    <?php /** * php生成验证码 * @param $width 画布宽 * @param $height 画布高 * @param $vcodelen 验证码长度 * @param $ ...

  10. 【MySQL】二进制分发安装

    操作系统:Red Hat Enterprise Linux Server release 6.5 Mysql安装包:mysql-5.6.34-linux-glibc2.5-x86_64.tar.gz ...