C/C++基础知识点(二)

文章目录

        • 13.C++如何定义常量,常量放在内存的哪个位置?
        • 14.const修饰成员函数的目的是什么?
        • 15.以下几行代码的区别?
        • 16.隐式类型转换
        • 17.new/delete与malloc/free的区别
        • 18. RTTI
        • 19.C++如何处理返回值
        • 20.C++中拷贝赋值函数的形参能否进行值传递?
        • 21.STL有什么基本组成
        • 22.STL中set和map如何实现的?
        • 23.STL迭代器如何删除元素
        • 24.vector和list的区别

13.C++如何定义常量,常量放在内存的哪个位置?

常量在C++里的定义是一个top-level const加上对象类型,常量定义必须初始化。对于局部对象,常量存放在栈区,对于全局对象,常量存放在全局/静态存储区。对于字面值常量,常量存放在常量存储区。

14.const修饰成员函数的目的是什么?

const修饰成员函数标明函数调用不会对对象作出任何更改,事实上,如果确认不会对对象做更改,就应该为函数加上const限定,这样无论const对象还是普通对象都可以调用该函数。

15.以下几行代码的区别?

const char * arr = "123"; //字符串123保存在常量区,const本身修饰arr指向的值不能通过arr去修改,但是字符串"123"在常量区,本来就不能修改,所以加不加const都一样的。
char * brr = "123"; //字符串"123"保存在常量区,这个arr指针指向的是同一个位置,同样不能用brr去修改"123"的值。
const char crr[] = "123"; //这里123本来是在栈上的,但是编译器可能会做某些优化,将其放到常量区。
char drr[] = "123";//字符串123保存在栈区,可以通过drr去修改。

16.隐式类型转换

首先,对于内置类型,低精度的变量给高精度变量赋值会发生隐式类型转换,其次,对于只存在单个参数的构造函数的对象构造来说,函数调用可以直接使用该参数传入,编译器会自动调用其构造函数生成临时对象。

17.new/delete与malloc/free的区别

首先,new/delete是C++的关键字,而malloc/free是C语言的库函数,后者使用必须指明申请内存空间的大小,对于类类型的对象,后者不会调用构造函数和析构函数。

18. RTTI

RTTI 全称:运行时类型检查。在C++层面主要体现在dynamic_cast和typeid,VS中虚函数表的-1位置存放了指向type_info的指针,对于存在虚函数的类型,typeid和dynamic_cast都会去查询type_info.

关于RTTI详细介绍请查看这里

19.C++如何处理返回值

生成一个临时变量,把它的引用作为函数参数传入函数内。

20.C++中拷贝赋值函数的形参能否进行值传递?

不能。如果是这种情况下,调用拷贝构造函数的时候,首先要将实参传递给形参,这个传递的时候又要调用拷贝构造函数,如此循环,无法完成拷贝,栈也会满。

21.STL有什么基本组成

STL主要由以下几个部分组成:容器、迭代器、仿函数、算法、分配器、配接器。
它们之间的关系:分配器给容器分配存储空间,算法通过迭代器获取容器中的内容,仿函数可以协助算法完成各种操作,配接器用来套接适配仿函数。

22.STL中set和map如何实现的?

  • set:集合。所有元素都会根据元素的值自动被排序,且不允许重复。底层实现:红黑树。
    set底层是通过红黑树(RB-tree)来实现的,由于红黑树是一种平衡二叉搜索树,自动排序的效果很不错,set以此为底层机制。并且set的所有操作接口,都是转调用RB-tree的操作。
    适用场景:有序不重复集合。
  • map:映射。map的所有元素都是pair,同时拥有键值key和实值value,pair的第一元素被视为键值,第二元素被视为实值,所有元素都会根据元素的键值自动被排序。不允许键值重复。底层实现用红黑树。
    适用场景:有序键值对不重复映射。

23.STL迭代器如何删除元素

1.对于序列容器vector,deque来说,适用erase(itertor)后,后边的每个元素的迭代器都会失效,后边的每个元素都会往前移动一个位置,但是erase会返回下一个有效的迭代器。

2.对于关联容器map,set来说,适用了erase(itertor)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。

3.对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的itertor,因此上面两种正确的方法都可以使用。

24.vector和list的区别

1.概念

  • vector:连续存储的容器,动态数组,在堆上分配空间,底层实现:数组。当vector增加新元素时,如果未超过当时的容量,则还有剩余空间,那么直接添加到最后,然后调整迭代器。如果没有空间了,就会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始化新空间,再向新空间添加元素,然后析构并释放原有空间,之前的迭代器会失效。
    性能:
    插入:在最后插入(空间够):很快
    在最后插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝
    在中间插入(空间够):内存拷贝
    在中间插入(空间不够):需要内存申请和释放,以及对之前的数据机型拷贝
    删除:在最后删除很快
    在中间删除:内存拷贝
    适用场景:经常随机访问,且不经常对非尾字节点进行插入删除。
  • list:动态链表,在堆上分配空间,每插入一个元素都会分配空间,每删除一个元素都会释放空间。底层实现:双向链表。
    性能:
    访问:随机访问性能很差,只能快速访问头尾节点
    插入:很快,一般是常数开销
    删除:很快,一般是常数开销
    适用场景:经常插入删除大量数据

2.区别

  • vector底层实现是数组,list底层实现是双向链表
  • vector支持随机访问,list不支持
  • vector是顺序内存,list不是
  • vector在中间节点进行插入删除会导致内存拷贝,list不会
  • vector随机访问性能好,插入删除性能差,list相反
  • vector一次性分配好内存,不够时才进行2倍扩容,list每次插入新节点都会进行内存申请

3.应用
vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随机访问,而不在乎删除和插入的效率,使用vector
list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,使用list


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部