1.智能指针:
- shared_ptr: 共享智能指针,使用引用计数进行生命周期管理。多个指针可以指向同一个对象。
- unique_ptr: 独占智能指针,采用移动语义,只能有一个指针独占对象。
- weak_ptr: 弱引用智能指针,用于配合shared_ptr,不影响对象生命周期。
优点:防止内存泄露,可以进行无显示删除。
缺点:智能指针开销较大,包含原始指针和控制块。
2.堆和栈的区别:
申请的方式不同,栈由系统自动分配,而堆是人为申请开辟。
申请大小的不同:栈获得的空间较小,堆获得的空间较大。
申请效率不同:栈由系统自动分配,速度较快,而堆一般速度较慢。
底层不同:栈是连续空间,而堆不是连续空间。
在程序内存布局场景下,堆与栈表示两种内存管理。
在数据结构场景下,堆与栈表示两种常用的数据结构。
程序内存中:
栈区(stack)--由编译器自动分配释放,存放函数的参数值,局部变量的名等。
堆区(heap)一般由程序员分配释放--new malloc,若程序员不释放,程序结束时可能由OS回收。
常数区(常量存储区):常量字符串,存储局部变量和全局变量的值。
静态区:存储的是全局变量和静态变量名。
代码区:二进制代码。
区域 | 作用 |
---|---|
内存栈区 | 存放局部变量名 |
内存堆区 | 存放new或者malloc出来的对象 |
常数区 | 存放局部变量或者全局变量的值 |
静态区 | 用于存放全局变量或者静态变量 |
代码区 | 二进制代码 |
常数区和静态区通常在编译期间就能确定存储大小的常量存储区,并且在程序运行期间,存储区内的常量是全局可见的。这是一块比较特殊的存储区,他们里边存放的是常量,不允许被修改。
内存存在两种属性:静态分配内存和动态分配内存。堆和栈都属于动态分配内存。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void before()
{
}
char g_buf[16]; //静态区 全局初始化区
char g_buf2[16];
char g_buf3[16];
char g_buf4[16];
char g_i_buf[]="123";
char g_i_buf2[]="123";
char g_i_buf3[]="123";
void after()
{
}
int main(int argc, char **argv)
{
char l_buf[16]; //栈区
char l_buf2[16];
char l_buf3[16];
static char s_buf[16]; // 全局初始化区
static char s_buf2[16];
static char s_buf3[16];
char *p_buf;//堆区 动态分配
char *p_buf2;
char *p_buf3;
p_buf = (char *)malloc(sizeof(char) * 16);
p_buf2 = (char *)malloc(sizeof(char) * 16);
p_buf3 = (char *)malloc(sizeof(char) * 16);
printf("g_buf: 0x%x\n", g_buf);
printf("g_buf2: 0x%x\n", g_buf2);
printf("g_buf3: 0x%x\n", g_buf3);
printf("g_buf4: 0x%x\n", g_buf4);
printf("g_i_buf: 0x%x\n", g_i_buf);
printf("g_i_buf2: 0x%x\n", g_i_buf2);
printf("g_i_buf3: 0x%x\n", g_i_buf3);
printf("l_buf: 0x%x\n", l_buf);
printf("l_buf2: 0x%x\n", l_buf2);
printf("l_buf3: 0x%x\n", l_buf3);
printf("s_buf: 0x%x\n", s_buf);
printf("s_buf2: 0x%x\n", s_buf2);
printf("s_buf3: 0x%x\n", s_buf3);
printf("p_buf: 0x%x\n", p_buf);
printf("p_buf2: 0x%x\n", p_buf2);
printf("p_buf3: 0x%x\n", p_buf3);
printf("before: 0x%x\n", before);
printf("after: 0x%x\n", after);
printf("main: 0x%x\n", main);
if (argc > 1)
{
strcpy(l_buf, argv[1]);
}
return 0;
}
3.C++ 中 死锁产生原因以及处理方法:
原因:
1.同时持有多个资源,而按不同顺序申请资源
2.资源无法抢占,进程触发等待条件,相互等待。
3.资源分配不当导致竞争和等待
死锁的必要条件:
1.互斥条件:资源被互斥使用,同时只能被一个进程占有
2.请求与保持条件:进程已获得的资源在申请新的资源前不释放。
3.不剥夺条件:其他进程无法强制剥夺正在被占用的资源
4.环路等待条件:形成环路进程等待图
解除死锁的方式:
1.防止形成环路等待条件,破坏环路等待条件。
2.使用顺序申请资源
3.设置资源申请超时时间,超过时间后,需要释放其他资源
4.提前规划资源分配,防止不合理的竞争与等待
5.允许抢占资源,破坏不剥夺条件
6.打破互斥条件,允许并发访问资源的某些部分
4.编程:数组内连续子数组大于指定数的个数
给定一个元素都是正整数的数组A,正整数L以及R(L<=R)。求连续、非空其中最大元素满足大于等于L小于等于R的子数组个数。例如:输入A=[2,1,4,3] L=2,R=3,输出:3,满足条件的子数组:[2],[2,1],[3]
# include <iostream>
#include <vector>
using namespace std;
//数组A中的数据分为三个部分,大于R的为分界线,当遇到大于R的数值的时候,count = 0;当元素在[L,R]之间的时候为i-j,因为连续所以i-j。当小于L的时候count和上一个元素的一样。
int numSubarrayBoundedMax(vector<int>&A, int L, int R) {
int j = -1;
int ans = 0;
int count = 0;
for(int i = 0; i < A.size(); i++ ){
if (A[i] > R) {
j = i;
}
if(A[i] >= L){
count = i - j;
}
ans +=count;
}
return ans;
}
5.unordered_map和map的主要区别是:
底层数据结构不同:
unordered_map底层使用哈希表实现,元素无序。
map底层常用红黑树实现,元素有序。
查询速度不同:
unordered_map查询速度很快,可达到O(1)复杂度;
map查询速度较unordered_map慢,为O(logn)复杂度;
接口略有不同:
unordered_map 没有 map 的 lower_bound、upper_bound 等函数。
实现原理:
unordered_map 使用哈希函数和桶来保存元素,通过关键字快速确定位置;
map 将元素保存在红黑树节点中,通过比较来维持元素键值有序。
综上,一般优先使用 unordered_map,除非需要顺序或自定义排序,才使用 map。空间换时间的原则。
C++中如果map的赋值key为自定义的类实现 。因为map中的key是有序的,所以自定义的类需要可以比较大小,需要重载小于操作符 operator < ()操作符。在我们插入<key, value>时,map会先通过比较函数地函数对象来比对key的大小,然后根据比对结果进行有序存储。c++标准库中,map比较函数的函数对象不可避免地会用到’<'运算,因此一种方法就是直接在自定义类里重载operator<()操作符,如下所示。
#include <iostream>
#include <map>
#include <string>
using namespace std;
class Person{
public:
string name;
int age;
Person(string n, int a){
name = n;
age = a;
}
bool operator<(const Person &p) const //注意这里的两个const
{
return (age < p.age) || (age == p.age && name.length() < p.name.length()) ;
}
};
int main(int argc, char* argv[]){
map<Person, int> group;
group[Person("Mark", 17)] = 40561;
group[Person("Andrew",18)] = 40562;
for (auto ii = group.begin() ; ii != group.end() ; ii++)
cout << ii->first.name
<< " " << ii->first.age
<< " : " << ii->second
<< endl;
return 0;
}
这里,我们需要注意的是,在重载operator<(){}时,无论是参数还是整个函数的const都不能少。参照less的定义,less的参数和函数整体都是const,那么被调用的operator<()必然也是同等要求。
6.引用和指针的区别:
1.引用访问一个变量是直接访问,而指针访问是间接访问。
2.引用是一个变量的别名,本身不单独分配内存空间,而指针有自己的内存空间。
3.引用指向某个对象之后就不可以改变,指针可以改变其所指的值。
4.不存在指向空值的引用,但是存在指向空值的指针。
5.引用是类型安全的,指针不是。
7.C++中动态链接库和静态链接库的区别:
常见的文件后缀:
动态链接库:Windows:.dll。Linux: .so。
静态链接库:Windows:.lib Linux:.a
静态链接会使可执行文件变得庞大,但具有更好的兼容性和运行速度;而动态链接则更加灵活,节省空间,但可能存在兼容性和性能的问题。
8.各种传感器的优缺点:
优点:
lidar:精度高,点云密度大,夜视能力强,探测距离远。可以提供物体准确的深度信息和结构信息。
camera:价格低,细节纹理丰富可以提供颜色信息。对小目标的识别效果好。
radar:成本低,可检测运动物体的速度。
缺点:
lidar:成本相对来说较高,对气候条件敏感(雨雪雾天气)。
camera:夜晚条件下检测效果差,对深度信息无法准确获得
radar:精准度低,有的时候会出现鬼影。