effective STL 读书笔记——第二章:vector和string

条款13:尽量使用vector和string来代替动态分配的数组

理由如下:

  1. 通过vector、string代替动态分配的数组,你可以享受标准stl算法库的好处
  2. 你不需要考虑何时放内存,不会存在麻烦的内存泄露问题
  3. 你不需要考虑到底是用delete还是delete[],也不需要顾虑资源重复释放的问题

使用容器代替动态分配的数组可能在以下2个地方存在问题:

  1. 由于STL实现的string可能存在引用计数,在多线程环境中使用了引用计数的字符串,你可能发现避免分配和拷贝所节省下的时间都花费在后台并发控制上了,但是它还是可以通过其他方式避免的,见 条款15
  2. 如果要构造bool的数组,但是选择了vector,它将存在问题,见 条款18

条款14:使用reserve来避免不必要的重新分配

对于序列容器四个关于容器大小的函数:

size():容器中有多少元素
capacity():容器在它已经分配的内存中可以容纳多少元素
resize():强制把容器改为容纳n个元素
reserve():强制容器把它的容量改为至少n,提供的n不小于当前大小(如果小于,则忽略)

对于vector其内存分配是以2为因数进行增长的,要注意如果进行push_back的时候,刚好要进行内存分配,则以前的迭代器都会失效。最好的办法是先判断capacity与size。而且由于默认的分配是以2为因数进行内存增长,为了避免频繁的分配内存,可以一次指定分配固定大小的内存,需要的时候再让其动态增长:

vector<int> v;
for (int i = 1; i <= 1000; ++i) v.push_back(i);// 未指定大小,push_back的过程中会多次分配内存

vector<int> v;
v.reserve(1000);// 指定元素个数,一次性分配好内存,避免频繁分配内存
for (int i = 1; i <= 1000; ++i) v.push_back(i);


string s;
//...
if (s.size() < s.capacity()) {
    s.push_back('x');
}

条款15:小心string实现的多样性

条款16: 如何将vector和string的数据传给遗留的API

如果需要兼容已存在的C-API的代码,要将元素作为数组传递给C函数,形式如下:

void dosomething(const int *pints,const int size);

你一定可以通过选择合适的容器来解决该问题。比如你的C++代码中,可以构建一个vector如下使用:

vector<int> vc;
// fill vc
dosomething(&vc[0],vc.size());// 使用时,应该检查vector非空

vc.begin()作为vector的迭代器起始地址,并不适合作为dosomtthing的参数,原因如下:

  1. vector的迭代替虽然一般情况下是以指针形式实现的,但是并不一直都是的,你不应该依赖它
  2. 如果由于某些原因,你要是用vc.begin(),应该使用&*v.begin()代替,但是它既不直观也不好写

如果需要字符串,可以使用string:

void doSomething(const char *pString);
doSomething(s.c_str());

当对容器的元素取地址,然后作为参数传递给C-API时,以下为约定的事情,否则可能引发未定义行为:

 被调用的函数绝不能试图改变vector中元素的个数——既不能增加元素个数,也不能减少元素个数

如果要将C-API返回值初始化一个vector,可以使用如下形式,只有vector可以使用如下形式,因为只有vector承诺了与数组具有相同的潜在内存分布:

// C API:此函数需要一个指向数组的指针,数组最多有arraySize个double
// 而且会对数组写入数据。它返回写入的double数,不会大于arraySize
size_t fillArray(double *pArray, size_t arraySize);
vector<double> vd(maxNumDoubles); // 建立一个vector,
// 它的大小是maxNumDoubles
vd.resize(fillArray(&vd[0], vd.size())); // 让fillArray把数据写入vd,然后调整vd的大小为maxNumDoubles

如果需要将C API返回值放入string,可以先将数据放入vector,然后再拷贝到string中:

// C API:此函数需要一个指向数组的指针,数组最多有arraySize个char
// 而且会对数组写入数据。它返回写入的char数,不会大于arraySize
size_t fillString(char *pArray, size_t arraySize);
vector<char> vc(maxNumChars); // 建立一个vector,
// 它的大小是maxNumChars
size_t charsWritten = fillString(&vc[0], vc.size()); // 让fillString把数据写入vc
string s(vc.begin(), vc.begin()+charsWritten); // 从vc通过范围构造函数
//deque<double> d(vd.begin(), vd.end()); // 拷贝数据到deque
//list<double> l(vd.begin(), vd.end()); // 拷贝数据到list
//set<double> s(vd.begin(), vd.end()); // 拷贝数据到set

条款17:使用“交换技巧”来修整过剩容量

虽然容器使用的内存能够动态的增长,也可以使用clear,erase删除容器中的元素,但是它并不回收真正的内存,直到容器被销毁。如果一个容器分配了10000个元素,最终留下的只有100个,如果删除已经不使用的内存?可以通过swap来完成
class Contestant {...};
vector<Contestant> contestants;
for(int i = 0;i < 10000;++i)
    contestants.push_back(i);
for(int i = 0;i < 9900;++i)
    contestants.pop_back();// 虽然元素被释放掉,但是以前使用过的内存没有被回收

// 通过vector<Contestant>(contestants)构造一个匿名变量,然后交换他们
vector<Contestant>(contestants).swap(contestants);

vector的构造函数,只为新的对象分配contestants.size()个元素容纳的内存,然后交换他们,匿名变量拥有原来较大的元素的空间,contestants拥有size个元素的空间,然后匿名变量马上析构掉。

同样的,string也可以通过这样的方式释放掉不需要的内存:

string s;
// 使s变大,然后删除所有
string(s).swap(s);

如果要清空容器并回收内存,并不是使用clear,而是使用以下方式:

vector<Contestant> v;
string s;
... // 使用v和s
vector<Contestant>().swap(v); // 清除v而且最小化它的容量
string().swap(s); // 清除s而且最小化它的容量

条款18:避免使用vector

vector的2个问题:

第一,它不是一个STL容器。
第二,它并不容纳bool

一个东西要成为STL容器必须满足一定的条件,至少要满足下面的这个必要条件:

如果c是一个T类型对象的容器,且c支持operator[],那么T *p = &c[0];必须能够编译 

vector<bool>实际上是一个标准容器库,但是它内部却不是使用的bool值作为成员变量,取而代之的是一个代理类,代理类把size个bool值对应到了每一位上,而且vector<bool>的[]操作并不是返回的bool的引用,而是通过代理类返回的一个临时的bool值,你不可能通过取地址符得到它在内存中的实际地址。

你可以使用deque和bitset代替vector。deque是一个标准库容器,但是其内存不是连续的,因此不能被传递给一个数组作为参数的C-API函数。bitset不是一个STL容器,但它是C++标准库的一部分。与STL容器不同,它的大小(元素数量)在编译期固定,因此它不支持插入和删除元素。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值