嵌入式c++软件开发第四讲笔记

简介: 嵌入式c++软件开发第四讲笔记

c++模板

概述

模板的作用

1.模板是一种参数化的多态工具

2.所谓参数化的多态性,是指将程序所处理的对象的类型参数化,使一段程序代码处理不同类型的对象。

3.采用模板编程,可以为各种逻辑功能相同而数据类型不同的程序提供一种代码共享机制

代码复用

函数模板 链接

template<模板形参表>

返回值类型 函数名(模板函数形参表){

函数定义体

}

模板被编译了两次;

模板的编译需要查看模板的定义;

类模板

template<类型形参表>

class <类名>

{

类说明体

}

类模板的使用

成员模板

实例化两个类,d和i,但是i却没法给d赋值。

成员模板的实现–链接

关键字-typename

内嵌依赖类型名

内嵌是指定义在类的定义中的

依赖是指依赖于一个模板参数typedef

类型名是指这里最终要指出的是个类型名

实例

链接

实例化

隐式实例化

函数模板隐式实例化指的是在发生函数调用的时候,如果没有发现相匹配的函数存在,编译器就会寻找同名函数模板,如果可以成功进行参数类型推演,就对函数模板进行实例化。

类模板隐式实例化指的是在使用模板类时才将模板实例化,相对于类模板显示实例化而言的

显示实例化

定义:显示实例化也称为外部实例化。在不发生函数调用的时候将函数模板实例化,或者在不使用类模板的时候将类模板实例化称之为模板显示实例化。

函数模板的显示实例化:template [函数返回类型] [函数模板名]<实际类型列表>(函数参数列表)例如:template void func(const int&);

类模板的显示实例化:template class [类模板名]<实际类型列表>

例如:template class theclass;

作用:减少隐式实例化实例多个函数和类的开销;最优化实例一次(不同编译器处理机制可能不同)

using给模板起别名

template
using str_map_t = std::map<std::string, Val>;
// …
str_map_t map1;

模板全特化与偏特化(C++11)

类模板的全特化

特化模板成员函数而不是模板

//模板泛化
template <typename T1, typename T2>
class A{
T1 data1;
T2 da ta2;
};
//模板全特化
template <>
class A<int, double>{
int data1;
double data2;
};
类模板的偏特化
//泛型化
template <typename T1,typename T2,typename T3>
class B
{
public:
void myfunc(T2 b)
{
cout << “泛化函数” << endl;
}
};
//偏特化:参数数量
template
class B<int, T2, int>
{
public:
void myfunc(T2 b)
{
cout << “偏特化函数” << endl;
}
};
参数范围变化:int–const int;T–T*; T–T&
//模板偏特化参数范围int–const int;T–T*; T–T&
template
class A {
public:
void myfunc()
{
cout << “const T偏特化函数” << endl;
}
};

函数模板全特化

注:函数模板不能偏特化

注:调用优先级:普通函数、重载函数、函数全特化

模板元编程

框架、库

Qt内部开发机制:模板元

c++内存管理

C语言内存管理

Linux虚拟内存空间分布

内存泄露——C语言没有更好的方法杜绝malloc的导致的内存泄漏

C++内存管理(1)

如何避免内存泄漏?

new/delete的使用

new/delete必须成对出现,new[]/delete []必须成对出现

人为的控制new/delete问题,无法杜绝内存泄漏

C++为什么没有提供GC机制?

1.没有共同基类:C++是从C发展而成,允许直接操作指针,允许将一个类型转换为另一个类型,对于一个指针无法知道它真正指向的类型;而Java或C#都有一个共同基类

2.系统开销:垃圾回收所带来的系统开销,违反了C++的设计哲学,“不为不必要的功能支付代价”,不符合C++高效的特性,使得不适合做底层工作

3.消耗内存:C++产生的年代内存很少,垃圾回收机制需要占用更多的内存

4.替代方法:C++有析构函数、智能指针、引用计数去管理资源的释放,对GC的需求不迫切

智能指针

作用:

帮助开发者对动态分配对象(new)的生命周期进行管理。能够有效防止内存泄漏

分类:

unique_ptr(C++11)–独占指针

shared_ptr(C++11)–共享指针

weak_ptr(C++11)–弱指针

shared_ptr

共享式指针:

多个指针可以同时指向同一个对象(共享所有权,协同工作),当最后一个指针被销毁或者指向其他对象时,这个对象会被释放;

工作原理:引用计数增加/减少(原子操作)

引用计数增加

用一个智能指针初始化另一个智能指针

函数传参:传递一个智能指针;

函数返回值:返回一个智能指针

引用计数减少

给智能指针赋予新值,指向一个新对象

局部的智能指针离开其作用域

定义:

shared_ptr<指向的类型> 智能指针变量名

shared_ptr是explicit,不可以进行隐式类型转换,只能直接初始化;

std::make_shared函数

auto p = std::make_shared(“hello world”);

功能:在 堆内存中可以动态分配对象,并返回一个shared_ptr;

推荐方法,因为此方法安全,高效;

shared_ptr常规操作

use_count();

功能:返回有多少个shared_ptr智能指针指向某对象;(引用计数的个数)

unique();

是否该智能指针独占某个对象,独占返回true,否则返回false;

reset();

reset()无参使用:若该智能指针是独占某个对象,则释放该对象,并将智能指针置nullptr;若不独占,引用计数减1,并将该指针置nullptr;

reset()代参使用:若该智能指针是独占某个对象,则释放该对象,并将该指针指向新对象;若不独占,则将该指针指向的对象引用计数减1,并将该指针指向新对象;

实例:p.reset();p.reset(new int());

*解应用

获得智能指针指向的对象,并对其操作;

get();

考虑到有些函数参数是裸指针并不是智能指针,所以需要将智能指针转化为裸指针;

获得智能指针中保存的指针(裸指针);

注:获得裸指针要小心使用,因为智能指针一旦释放,裸指针也就失效;

= nullptr;

将该智能指针引用计数减1,并置nullptr,若引用计数为零,将指向对象释放;

指定删除器

why:有些情况,默认删除器处理不了(shared_ptr管理动态数组),需要我们自己指定删除器;

实例–链接

移动语义:std::move();

weak_ptr

概述

1.weak_ptr弱指针,不会控制对象的生命周期(不会改变对象的引用计数),shared_ptr释放指向对象时,是不会考虑weak_ptr是否指向该对象

2.weak_ptr不是独立指针,不能单独操作所指向的资源;

作用

1.weak_ptr指针一般用来辅助shared_ptr的使用(监视shared_ptr指向对象的生命周期)

2.weak_ptr和shared_ptr之间可以相互转换,shared_ptr可以直接赋值给weak_pt,但是反过来是行不通的,需要使用lock函数。

weak_ptr的常规操作

lock();

调用lock函数来获得shared_ptr(如果对象已经被释放,则返回一个空的shared_ptr)

use_count();

功能:返回有多少个shared_ptr智能指针指向某对象;(引用计数的个数)

expired();

判断弱指针是否过期(所检测的对象是否被释放true/false)

reset();

将该弱指针设置为空,弱引用计数减1,强引用计数不变

shared_ptr & weak_ptr

尺寸

shared_ptr和weak_ptr一样大,是裸指针的两倍;

常见使用问题

shared_ptr多次引用同一数据,会导致两次释放同一内存

使用shared_ptr包装this指针导致局部对象会释放两次-解决办法: enable_shared_from_this模板类

shared_ptr循环引用导致内存泄露

unique_ptr

独占式指针(专属所有权)

同一时刻,只能有一个unique_ptr指向这个对象;当指针销毁,指向的对象也销毁;

初始化

手动初始化:unique_ptr p;或unique p(new int(5))

std::make_unique函数(C++14)

unique_ptr常规操作

不支持操作:该指针不支持拷贝和赋值操作;

移动语义std::move();

release();

放弃对指针的控制权,将该指针置nullptr,返回裸指针;

reset();

reset()无参使用:若该智能指针是独占某个对象,则释放该对象,并将智能指针置nullptr;

reset()代参使用:若该智能指针是独占某个对象,则释放该对象,并将该指针指向新对象;

实例:p.reset();p.reset(new int());

*解应用

获得智能指针指向的对象,并对其操作;

get();

获得智能指针中保存的指针(裸指针);

= nullptr;

将该智能指针引用计数减1,并置nullptr,若引用计数为零,将指向对象释放;

指定删除器

语法:unique_ptr<指向对象类型,删除器的类型> 智能指针变量名

自定义删除函数

void mydeleter(string *s)
{
delete s;
}
using MYFUNC = void (*)(string *);// tyepdef void (*MYFUNC)(string *);
unique_ptr<string,MYFUNC> p(new string(“hello world”),mydeleter);
lambda函数—decltype()
auto mydeleter = [](string *s)
{
delete s;
};
unique_ptr<string,decltype(mydeleter)> p(new string(“hello world”),mydeleter);

指定不同的删除器会导致不同的unique_ptr;

unique_ptr尺寸:

和裸指针一样大,但是指定自定义删除函数会影响尺寸大小;

C++内存管理(2)

内存池

起因:malloc:内存浪费,频繁分配小块内存,则浪费更加显得明显

作用:减少malloc的次数,减少malloc()调用次数就意味着减少对内存的浪费

原理:用malloc申请一大块内存,当要分配的时候,从这一大块内存中一点一点的分配,当一大块内存分配的差不多的时候,再用malloc再申请一大块内存,然后再一点一点的分配给你

内存池的实现v1.0–问题:next指针占用4个字节,每块内存都存在next指针,导致空间的浪费–链接

内存池的实现v2.0

嵌入式指针–链接

使用嵌入式指针改进内存池–链接

总结

C++内存管理的特点(智能指针)

智能指针的种类及使用

区分new operator(全局new)、operator new

重载各类版本的operator new

placement new的作用理解

内存池的实现

目录
相关文章
|
5月前
|
编译器 C++
《Effective C++ 改善程序与设计的55个具体做法》 第一章 笔记
《Effective C++ 改善程序与设计的55个具体做法》 第一章 笔记
|
3月前
|
C++
拥抱C++面向对象编程,解锁软件开发新境界!从混乱到有序,你的代码也能成为高效能战士!
【8月更文挑战第22天】C++凭借其强大的面向对象编程(OOP)能力,在构建复杂软件系统时不可或缺。OOP通过封装数据和操作这些数据的方法于对象中,提升了代码的模块化、重用性和可扩展性。非OOP方式(过程化编程)下,数据与处理逻辑分离,导致维护困难。而OOP将学生信息及其操作整合到`Student`类中,增强代码的可读性和可维护性。通过示例对比,可以看出OOP使C++代码结构更清晰,特别是在大型项目中,能有效提高开发效率和软件质量。
33 1
|
3月前
|
C++ 容器
【C/C++笔记】迭代器
【C/C++笔记】迭代器
25 1
|
3月前
|
存储 安全 程序员
【C/C++笔记】迭代器范围
【C/C++笔记】迭代器范围
66 0
|
4月前
|
C++ Windows
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
在Windows上使用Visual Studio 2022进行FFmpeg和SDL2集成开发,首先安装FFmpeg至E:\msys64\usr\local\ffmpeg,然后新建C++控制台项目。在项目属性中,添加FFmpeg和SDL2的头文件及库文件目录。接着配置链接器的附加依赖项,包括多个FFmpeg及SDL2的lib文件。在代码中引入FFmpeg的`av_log`函数输出"Hello World",编译并运行,若看到"Hello World",即表示集成成功。详细步骤可参考《FFmpeg开发实战:从零基础到短视频上线》。
157 0
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
|
5月前
|
编译器 C++
《Effective C++ 改善程序与设计的55个具体做法》 第二章 构造/析构/赋值运算 笔记
《Effective C++ 改善程序与设计的55个具体做法》 第二章 构造/析构/赋值运算 笔记
|
5月前
|
存储 小程序 程序员
Essential C++ 第1章 C++编程基础 (笔记)
Essential C++ 第1章 C++编程基础 (笔记)
|
5月前
|
算法 C语言 C++
面向考试编程C++笔记
面向考试编程C++笔记
|
6天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
29 4
|
7天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
25 4