C++常见问题归纳(二)

  1. 内存泄漏
    ·内存泄漏(memory leak):指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
    ·内存泄漏的分类:
    堆内存泄漏(Heap leak)。对内存指的是程序运行中根据需要分配通过malloc,realloc,new等从堆中分配的一块内存,再是完成后必须通过调用对应的free或者delete删掉。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak。
    系统资源泄露(Resource Leak)。主要指程序使用系统分配的资源比如Bitmap,handle,SOCKET等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。
    没有将基类的析构函数定义为虚函数。当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露。

  2. map和set的区别
    ·map和set都是C++的关联容器,其底层实现都是红黑树。几乎所有的map和set的操作行为,都只是转调RB-tree的操作行为。
    ·map和set区别在于:
    ①map中的元素是key-value(关键字一值)对:关键字起到素引的作用,值则表示与索引相关联的数据;set的元素就是关键字的简单集合,set中每个元素只包含一个关键字。
    set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。因为map和set是根据关键字排序来保证其有序性的,如果允许修改key的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了map和set的结构,导致iterator失效,不知道应该指向改变前的位置,还是指向改变后的位置。所以STL中将set的迭代器设置成const,不允许修改迭代器的值;而map的迭代器则不允许修改key值,允许修改value值。
    map支持下标操作,set不支持下标操作。map可以用key做下标,map的下标运算符[]将关键码作为下标去执行查找,如果关键码不存在,则插入一个具有该关键码和mapped_type类型默认值的元素至map中,因此下标运算符[]在map应用中需要慎用,const_map不能用,只希望确定某一个关键值是否存在而不希望插入元素时也不应该使用,mapped_type类型没有默认值也不应该使用。如果find能解决需要,尽可能用find。

  3. STL迭代器删除元素
    序列容器 vector,deque:使用erase(itertor)后,后边的每个元素的迭代器都会失效,但是后边每个元素都会往前移动一个位置,但是erase会返回下一个有效的迭代器;
    关联容器map,set:使用了rase(iterator)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可;
    list:使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用。

  4. vector和list的区别
    ·概念:
    Vector:连续存储的容器,动态数组,在堆上分配空间。
    底层实现:数组。
    两倍容量增长:
    vector 增加(插入)新元素时,如果未超过当时的容量,则还有剩余空间,那么直接添加到最后(插入指定位置),然后调整迭代器。
    如果没有剩余空间了,则会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始化新空间,再向新空间增加元素,最后析构并释放原空间,之前的迭代器会失效。
    性能:访问:O(1)。
    插入:在最后插入(空间够)很快;在最后插入(空间不够)需要内存申请和释放,以及对之前数据进行拷贝;在中间插入(空间够)内存拷贝;在中间插入(空间不够)需要内存申请和释放,以及对之前数据进行拷贝。
    删除:在最后删除很快;在中间删除内存拷贝。
    适用场景:经常随机访问,且不经常对非尾节点进行插入删除。
    List:动态链表,在堆上分配空间,每插入一个元数都会分配空间,每删除一个元素都会释放空间。
    底层:双向链表。
    性能:
    访问:随机访问性能很差,只能快速访问头尾节点。
    插入:很快,一般是常数开销。
    删除:很快,一般是常数开销。
    适用场景:经常插入删除大量数据。
    ·区别
    ①vector底层实现是数组;list是双向链表。
    ②vector支持随机访问,list不支持。
    ③vector是顺序内存,list不是。
    ④vector在中间节点进行插入删除会导致内存拷贝,list不会。
    ⑤vector一次性分配好内存,不够时才进行2倍扩容;list每次插入新节点都会进行内存申请。
    ⑥vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。
    ·应用
    ①vector 拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。
    ②list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。

  5. STL中map、multimap与unordered_map
    ·三者所有元素都是pair,同时拥有实值(value)和键值(key)。pair的第一元素被视为键值,第二元素被视为实值。
    ①map映射:所有元素都会根据元素的键值自动被排序。不允许键值重复。
    底层实现:红黑树。
    适用场景:有序键值对不重复映射。

    ②multimap多重映射:所有元素都会根据元素的键值自动被排序。允许键值重复。
    底层实现:红黑树。
    适用场景:有序键值对可重复映射。

    ③unordered_map映射:元素不会根据元素的键值排序。不允许键值重复。
    底层实现:哈希表。
    适用场景:无序键值对不重复映射。

  6. C++11有哪些新特性
    auto关键字:编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导。
    nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。
    智能指针:C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题。
    初始化列表:使用初始化列表来对类进行初始化。
    右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
    atomic原子操作用于多线程资源互斥操作。
    ⑦新增 STL容器array以及tuple

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值