cpp primer笔记090-动态内存

2023-10-07 09:01

本文主要是介绍cpp primer笔记090-动态内存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. shared_ptr和unique_ptr都支持的操作,加上shared_ptr独有的操作
    ![[Pasted image 20230923103844.png]]

![[Pasted image 20230923103855.png]]

  1. 每个shared_ptr都有一个关联的计数器,通常称其为引用计数,当调用了shared_ptr的构造函数时就会递增,当调用析构函数时就会递减,一旦一个shared_ptr的计数器为0的时候,它就会自动释放自己所管理的对象。
    #include <iostream>
    #include <fstream>
    #include <array>
    #include <vector>
    #include <string>
    #include <exception>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <numeric>
    #include <memory>
    int main()
    {std::shared_ptr<int> ptr1 = std::make_shared<int>(10);std::cout << ptr1.unique() << " " << ptr1.use_count() << std::endl;std::shared_ptr<int> ptr2 = std::make_shared<int>(10);std::cout << ptr1.unique() << " " << ptr1.use_count() << std::endl;
    std::shared_ptr<int> ptr3(ptr1);
    std::cout << ptr1.unique() << " " << ptr1.use_count() << std::endl;
    

}
cpp
1 1
1 1
0 2

```
  1. 如果想让STL的容器产生类似于shared_ptr指针的效果,可以进行下面的操作:(如果一个shared_ptr指向的对象的引用次数为0,则该对象会被销毁)

    #include <iostream>
    #include <fstream>
    #include <array>
    #include <vector>
    #include <string>
    #include <exception>
    #include <algorithm>
    #include <deque>
    #include <numeric>
    #include <memory>
    #include <initializer_list>
    #include <exception>
    class StrBlob
    {
    public:typedef std::vector<std::string>::size_type size_type;StrBlob() :data(std::make_shared<std::vector<std::string>>()) {};StrBlob(std::initializer_list<std::string> il) :data(std::make_shared<std::vector<std::string>>(il)) {};StrBlob(std::vector<std::string> vec) :data(std::make_shared<std::vector<std::string>>(vec)) {};~StrBlob() = default;size_type size() const;void push_back(const std::string& t);void pop_back();std::string front() const;std::string back() const;auto cbegin() -> decltype(std::cbegin(std::vector<std::string>()));auto cend() -> decltype(std::cend(std::vector<std::string>()));
    private:std::shared_ptr<std::vector<std::string>> data;void check(size_type i, const std::string& msg) const throw(const std::string&);
    };
    std::vector<std::string>::size_type StrBlob::size() const
    {return data->size();
    }void StrBlob::push_back(const std::string& t)
    {data->push_back(t);
    }void StrBlob::pop_back()
    {data->pop_back();
    }std::string StrBlob::front() const
    {check(0, "front on empty StrBlob");return data->front();
    }std::string StrBlob::back() const
    {check(0, "back on empty StrBlob");return data->back();
    }void StrBlob::check(std::vector<std::string>::size_type i, const std::string& msg) const throw(const std::string&)
    {if (i >= data->size()){throw std::out_of_range(msg);}
    }auto StrBlob::cbegin() -> decltype(std::cbegin(std::vector<std::string>()))
    {return this->data->cbegin();
    }auto StrBlob::cend() -> decltype(std::cend(std::vector<std::string>()))
    {return this->data->cend();
    }int main()
    {StrBlob str1({ "123", "fsdf","zcxv" });StrBlob str2 = str1;str1.push_back("sdfsdfz");str1.~StrBlob();std::ostream_iterator<std::string> os(std::cout, " ");std::for_each(str2.cbegin(), str2.cend(), [&os](std::string val) { os = val; });return 0;
    }
    
    123 fsdf zcxv sdfsdfz
    
  2. 智能指针不允许进行内置指针到智能指针间的隐式转换,只能显示转换。下面是shared_ptr和new结合使用的各种函数

    #include <iostream>
    #include <fstream>
    #include <array>
    #include <vector>
    #include <string>
    #include <exception>
    #include <algorithm>
    #include <deque>
    #include <numeric>
    #include <memory>
    #include <initializer_list>
    #include <exception>
    std::shared_ptr<int> clone(int p)
    {//return new int(p);不能隐式转换return std::shared_ptr<int>(new int(p));
    }
    int main()
    {std::shared_ptr<int> ptr1;std::shared_ptr<double> ptr2(new double(42));//可以通过构造函数转换//std::shared_ptr<int> ptr3 = new int(1024);不能隐式转换return 0;
    }
    

    ![[Pasted image 20230923144221.png]]

    ![[Pasted image 20230923153455.png]]

    ![[Pasted image 20230923161047.png]]

  3. 不要混用普通指针和智能指针,尽量都是用智能指针,如果混用二者会产生以下未定义行为。智能指针相对于普通指针的区别有当函数使用智能指针的时候,如果抛出异常,则栈解退的时候会自动调用析构函数释放内存,而使用普通指针的时候则不会delete掉

    void process(std::shared_ptr<int> ptr)
    {;
    }
    int main()
    {std::shared_ptr<int> p(new int(42));process(p);int i = *p;std::cout << i << std::endl;int* x(new int(1024));//process(x); 不能将int*显式转换为一个shared_ptr<int>()类型的指针process(std::shared_ptr<int>(x));//如果将x显式类型转换,则可能导致x的内存被释放int j = *x;//未定义行为:x是一个悬空指针!std::cout << j << std::endl;return 0;
    }
    
    42
    -572662307
    
  4. unique_ptr操作,一般情况下是不允许拷贝unique_ptr,但是如果从函数返回一个unique_ptr值或者返回一个局部对象拷贝的情况下是允许的。
    ![[Pasted image 20230923154021.png]]

![[Pasted image 20230923161112.png]]

	#include <vector>#include <string>#include <exception>#include <algorithm>#include <deque>#include <numeric>#include <memory>#include <initializer_list>#include <exception>std::unique_ptr<std::string> clone1(std::string str){return std::unique_ptr<std::string>(new std::string(str));}std::unique_ptr<std::string> clone2(std::string str){std::unique_ptr<std::string> ret(new std::string(str));return ret;}int main(){std::unique_ptr<std::string> ptr1(new std::string("sjkdfskdf"));std::unique_ptr<std::string> ptr2(ptr1.release());std::unique_ptr<std::string> ptr3(new std::string("kxcnsd"));std::cout << *ptr2 << std::endl;ptr2.reset(ptr3.release());std::cout << *ptr2 << std::endl;return 0;}
  1. weak_ptr的一些操作:
    ![[Pasted image 20230923160922.png]]

  2. 由于分配的内存并不是一个数组类型,因此不能对动态数组调用begin和end函数,也不能用范围for语句来处理动态数组中的元素,我们所说的动态数组并不是数组类型

  3. 指向数组的unique_ptr支持一下操作,由于shared_ptr不支持通过[]访问的操作,因此需要使用get函数。
    ![[Pasted image 20230923163322.png]]

	#include <iostream>#include <fstream>#include <array>#include <vector>#include <string>#include <exception>#include <algorithm>#include <deque>#include <numeric>#include <memory>#include <initializer_list>#include <exception>int main(){std::unique_ptr<int[]> up(new int[10]);std::shared_ptr<int> sp(new int[10], [](int* p) {delete[] p; });for (size_t i = 0; i != 10; ++i){up[i] = i;*(sp.get() + i) = 2 * i;}for (size_t i = 0; i < 10; ++i){std::cout << up[i] << "/" << *(sp.get() + i) << " ";}return 0;}
  1. allocate的使用:
    ![[Pasted image 20230923170327.png]]
	#include <iostream>#include <fstream>#include <array>#include <vector>#include <string>#include <exception>#include <algorithm>#include <deque>#include <numeric>#include <memory>#include <initializer_list>#include <exception>int main(){int n;std::allocator<std::string> alloc;//可以分配string内存的allocator对象std::cin >> n;auto const start = alloc.allocate(n);//分配十个内存,start是指向该内存开头的指针auto end = const_cast<decltype(alloc.allocate(n))>(start);//end即构造完成的内存的下一个位置alloc.construct(end++, 10, 'c');//构造一个含有10个c的字符串alloc.construct(end++, "sdfksd");//构造一个sdfksd的字符串for (auto it = start; it != end; ++it){std::cout << *it << " ";//输出已经构造的空间的字符串}std::cout << std::endl;alloc.destroy(--end);//重置一个已经构造的空间,但是并不会销毁for (auto it = start; it != end; ++it){std::cout << *it << " ";}alloc.deallocate(start, n);//销毁所有已分配的空间return 0;}
	5cccccccccc sdfksdcccccccccc

![[Pasted image 20230923171456.png]]在这里插入图片描述

	#include <iostream>#include <fstream>#include <array>#include <vector>#include <string>#include <exception>#include <algorithm>#include <deque>#include <numeric>#include <memory>#include <initializer_list>#include <exception>int main(){std::allocator<int> a,b;auto beginPtrA = a.allocate(10);auto beginPtrB = b.allocate(10);std::uninitialized_fill_n(beginPtrA, 10, 5);for (size_t i = 0; i < 10; ++i){std::cout << *(beginPtrA + i) << " ";}std::cout << std::endl;std::uninitialized_copy_n(beginPtrA, 10, beginPtrB);for (size_t i = 0; i < 10; ++i){std::cout << *(beginPtrA + i) << " ";}return 0;}
5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5
  1. 智能指针shared_ptr和unique_ptr重载删除器,都可以用普通函数,仿函数和未捕获任何类型的lambda表达式,但是unique需要传递一个函数指针
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <string>
    #include <memory>
    #include <deque>
    #include <vector>
    #include <algorithm>
    #include <functional>
    void deleter(int* x)
    {std::cout << "普通函数删除器" << std::endl;delete[] x;
    }
    class Deleter
    {
    public:void operator() (int* x) {std::cout << "仿函数删除器" << std::endl;delete[] x;}
    };int main() 
    {std::shared_ptr<int> shPtr1(new int[5], deleter);std::shared_ptr<int> shPtr2(new int[2], std::function<void(int*)>(Deleter()));std::shared_ptr<int> shPtr3(new int[7], [](int* x) {std::cout << "lambda表达式删除器" << std::endl;delete[] x;});std::unique_ptr<int[], std::function<void(int*)>> unPtr1(new int[5], deleter);std::unique_ptr<int[], std::function<void(int*)>> unPtr2(new int[6], std::function<void(int*)>(Deleter()));std::unique_ptr<int[], std::function<void(int*)>> unPtr3(new int[7], [](int* x) {std::cout << "lambda表达式删除器" << std::endl;delete[] x;});return 0;
    }

这篇关于cpp primer笔记090-动态内存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/157369

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

忽略某些文件 —— Git 学习笔记 05

忽略某些文件 忽略某些文件 通过.gitignore文件其他规则源如何选择规则源参考资料 对于某些文件,我们不希望把它们纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常它们都是些自动生成的文件,比如日志文件、编译过程中创建的临时文件等。 通过.gitignore文件 假设我们要忽略 lib.a 文件,那我们可以在 lib.a 所在目录下创建一个名为 .gi

取得 Git 仓库 —— Git 学习笔记 04

取得 Git 仓库 —— Git 学习笔记 04 我认为, Git 的学习分为两大块:一是工作区、索引、本地版本库之间的交互;二是本地版本库和远程版本库之间的交互。第一块是基础,第二块是难点。 下面,我们就围绕着第一部分内容来学习,先不考虑远程仓库,只考虑本地仓库。 怎样取得项目的 Git 仓库? 有两种取得 Git 项目仓库的方法。第一种是在本地创建一个新的仓库,第二种是把其他地方的某个