面试之CPP基础知识-8


#类的对象存储空间?

  1. 类的非静态成员变量大小,静态成员不占据类的空间,成员函数也不占据类的空间大小;

  2. 内存对齐另外分配的空间大小;

  3. 虚函数会在类对象插入vptr指针,加上指针大小;

  4. 基类的数据成员也会存在派生类中的空间。

#简要说明C++的内存分区

C++中的内存分区,分别是堆、栈、全局/静态存储区、常量存储区和代码区。如下图所示

image

:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限

:由 new分配的内存块,需要应用程序去控制,newdelete要对应。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收

全局/静态存储区:全局变量和静态变量被分配到同一块内存中,~~在以前的C语言中,全局变量和静态变量又分为初始化的和未初始化的,在C++里面没有这个区分了,~~在该区定义的变量若没有初始化,则会被自动初始化,例如int型变量自动初始为0

常量存储区:这是一块比较特殊的存储区,这里面存放的是常量,不允许修改

代码区:存放函数体的二进制代码

#什么是内存池,如何实现

  • 内存池(Memory Pool)是一种动态内存分配与管理技术,通常情况下,程序员习惯直接使用new,delete,malloc,free等API申请和释放内存,这样导致的后果就是:当程序运行的时间很长的时候,由于所申请的内存块的大小不定,频繁使用时会造成大量的内存碎片从而降低程序和操作系统的性能。
  • 内存池则是在真正使用内存之前,先申请分配一大块内存(内存池)留作备用。当程序员申请内存时,从池中取出一块动态分配,当程序员释放时,将释放的内存放回到池内,再次申请,就可以从池里取出来使用,并尽量与周边的空闲内存块合并。若内存池不够时,则自动扩大内存池,从操作系统中申请更大的内存池。

https://zhuanlan.zhihu.com/p/523216209

#C++的内存管理?

在C++中,内存分成5个区,他们分别是堆、栈、全局/静态存储区和常量存储区和代码区。

:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限

:由 new分配的内存块,需要应用程序去控制,newdelete要对应。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收

全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量和静态变量又分为初始化的和未初始化的,在C++里面没有这个区分了, 在该区定义的变量若没有初始化,则会被自动初始化,例如int型变量自动初始为0

常量存储区:这是一块比较特殊的存储区,这里面存放的是常量,不允许修改

代码区:存放函数体的二进制代码

#C++中类的数据成员和成员函数内存分布情况

类的首地址为声明的第一个成员变量的地址。成员变量保存在栈或堆中,成员函数保存在代码段

https://zhuanlan.zhihu.com/p/512762755

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;

class Person
{
public:
    Person()
    {
        this->age = 23;
    }
    void printAge()
    {
        cout << this->age <<endl;
    }
    ~Person(){}
public:
    int age;
    const int a = 5;
    static int b;
};

int main()
{
    Person p;
    cout << "对象地址:"<< &p <<endl;
    cout << "age地址:"<< &(p.age) <<endl;
    cout << "对象大小:"<< sizeof(p) <<endl;
    return 0;
}
//输出结果
//对象地址:0x7fffec0f15a8
//age地址:0x7fffec0f15a8
//对象大小:8

所有函数都存放在代码区,静态函数也不例外。一看到 static 这个单词就主观的认为是存放在全局数据区,那是不对的。

#关于this指针你知道什么?

  1. this 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向调用该成员函数的那个对象。
  2. this 指针被隐含地声明为: ClassName *const this,这意味着不能给 this指针赋值
  3. this 并不是一个常规变量,而是个右值,所以不能取得 this的地址
  4. this在成员函数的开始执行前构造,在成员函数的执行结束后清除。
  5. A a; a.fun(); // aka a.fun(this)
  6. 在以下场景中,经常需要使用 this 指针:
    1. 为实现对象的链式引用
    2. 为避免对同一对象进行赋值操作;
    3. 在实现一些数据结构时,如 list

#内存泄漏的后果?如何监测?解决方法?

你觉得会问吗

1) 内存泄漏

内存泄漏是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况,导致程序无法再次利用这段内存。

2) 后果

只发生一次小的内存泄漏可能不被注意,但泄漏大量内存的程序将会出现各种症状:性能下降到内存逐渐用完,导致另一个程序失败;

3) 如何排除

使用工具软件BoundsChecker,BoundsChecker是一个运行时错误检测工具,它主要定位程序运行时期发生的各种错误;

调试运行DEBUG版程序,运用以下技术:CRT(C run-time libraries)、运行时函数调用堆栈、内存泄漏时提示的内存分配序号(集成开发环境OUTPUT窗口),综合分析内存泄漏的原因,排除内存泄漏。

4) 解决方法

智能指针。

5) 检查、定位内存泄漏

检查方法:在main函数最后面一行,加上一句_CrtDumpMemoryLeaks()。调试程序,自然关闭程序让其退出,查看输出:

输出这样的格式{453}normal block at 0x02432CA8,868 bytes long

被{}包围的453就是我们需要的内存泄漏定位值,868 bytes long就是说这个地方有868比特内存没有释放。

定位代码位置

在main函数第一行加上_CrtSetBreakAlloc(453);意思就是在申请453这块内存的位置中断。然后调试程序,程序中断了,查看调用堆栈。加上头文件#include <crtdbg.h>

#在成员函数中调用delete this会出现什么问题?对象还可以使用吗?

当 调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。

为什么是不可预期的问题?

这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是一串很长的未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。

在析构函数中调用delete this 会导致堆栈溢出,因为delete调用析构,而析构再次调用delete。

https://blog.csdn.net/qq_39661275/article/details/106373853

#你知道空类的大小是多少吗?

笔试做到过

  1. 空类(没有非静态数据成员)的对象的size为1, 当作为基类时, size为0。因为标准规定是0,因为每个类需要独一无二的地址,防止出现除0错误。
  2. 带有虚函数的C++类大小不为1,因为每一个对象会有一个vptr指向虚函数表,具体大小根据指针大小确定;

#这几个类的大小是多少?

1
2
3
4
5
6
7
8
9
class A {};
class B{ virtual void func(){} };
class C{ static int a; };
int main(){
  cout<<sizeof(A)<<endl;// 输出 1; 
  cout<<sizeof(B)<<endl;// 输出 8;
  cout<<sizeof(C)<<endl;// 输出 1;
  return 0;
}

#this指针调用成员变量时,堆栈会发生什么变化?

this指针首先入栈,然后成员函数的参数从右向左进行入栈,最后函数返回地址入栈。

#类对象的大小受哪些因素影响?

  1. 类的非静态成员变量大小,静态成员不占据类的空间,成员函数也不占据类的空间大小;

  2. 内存对齐另外分配的空间大小;

  3. 虚函数会在类对象插入vptr指针,加上指针大小;

  4. 基类的数据成员也会存在派生类中的空间。

  5. http://baiy.cn/doc/cpp/inside_rtti.htm