博客
关于我
后端开发面试题
阅读量:245 次
发布时间:2019-03-01

本文共 5476 字,大约阅读时间需要 18 分钟。

C++中的关键字解析

C++中常见的关键字包括volatilestaticconstextern等,这些关键字在编程中发挥着重要作用。

volatile作用

volatile关键字用于标记变量,表示这些变量的值可能会被外部程序修改。这种情况比较少见,主要用于与I/O操作相关的变量。

static修饰局部变量

static用于修饰局部变量,通常存放在静态数据区(即内存),其生命周期持续到程序结束。与非static局部变量相比,static变量不会自动释放。例如:

int a; // 局部变量,存放在栈中,生命周期在语句块结束时终止static int b; // 存放在静态数据区,生命周期持续到程序结束

需要注意的是,static修饰的局部变量仍然是局部变量,作用域仅限于当前语句块。

static修饰全局变量

全局变量默认可在整个程序中访问。通过static修饰,全局变量的作用域被限制为当前文件,其他文件无法访问。例如:

// 全局变量可在多个文件中使用,需用`extern`声明int global_var; // 非`static`全局变量,作用域为整个程序static int static_var; // 作用域仅限于当前文件

static修饰函数

static修饰函数时,函数不能被外部文件调用,仅在当前文件中可用。例如:

// 非`static`函数可被外部文件调用void func1();// `static`函数仅在当前文件中可用static void func2();

static在类中的用法

在类中使用static修饰成员函数或变量,可改变其访问级别。例如:

class MyClass {public:    static void func(); // 静态成员函数,属于类而非对象    static const int MAX = 100; // 静态常量,仅在类中使用};

const的含义及实现机制

const是C++中的常量限定符,用于标记不可修改的变量或函数返回值。const的主要作用是确保编译时能识别不可修改的变量,从而避免潜在的错误。

const修饰基本数据类型

const可以修饰基本数据类型,如整数、字符和布尔值。这些常量在程序中不可修改。例如:

const int MAX_VAL = 100; // 常量const char *str = "Hello"; // 常量字符串

const修饰指针和引用

const也可以修饰指针和引用变量。例如:

const int *ptr = &MAX_VAL; // 指针指向常量const int &ref = MAX_VAL; // 引用常量

需要注意的是,const的位置会影响其作用范围。如果const在星号左侧,则指针指向常量;如果在右侧,则指针本身是常量。

const在函数中的用法

在函数中,const可以修饰参数和返回值。例如:

void func(const int *ptr); // 参数为常量指针int func2() const; // 返回值为常量

const参数通常用于指针或引用,以确保函数不会修改外部的可变数据。

const在类中的用法

在类中,const用于定义常量成员或成员函数。例如:

class MyClass {public:    const int MAX = 100; // 常数成员    void func() const; // 常函数,不能修改对象属性};

需要注意的是,常数成员在类构造函数中初始化。

extern的作用

extern用于声明外部定义的变量或函数,使其在当前文件中可用。例如:

// 在其他文件定义int GLOBAL_VAR = 10;extern int GLOBAL_VAR; // 在当前文件中使用GLOBAL_VAR

宏和内联函数的区别

宏是预处理器在编译前对代码进行的文本替换。宏没有类型检查,可能带来安全隐患,但展开速度快。

内联函数

内联函数(inline functions)是编译器在调用时直接展开的函数,避免了函数调用的开销。内联函数支持参数检查和异常处理,相比宏更安全。

区别

  • :由预处理器处理,代码在编译前替换,缺乏类型和范围检查。
  • 内联函数:由编译器处理,支持类型检查和范围检查,适用于函数体较小的情况。

宏和内联函数的主要区别在于处理方式:宏是预处理,内联函数是编译时展开。

库函数实现:malloc、strcopy、strcmp

malloc

malloc函数用于动态内存分配,返回指向内存的指针。需要手动释放内存。例如:

void* p = malloc(100); // 分配100字节内存free(p); // 释放内存

malloc的实现通常使用 Arena 分配策略,适用于大块内存分配。

strcopy和strcmp

strcopystrcmp是字符串处理库函数。strcopy复制字符串内容,strcmp比较字符串内容。例如:

char* dest = new char[dest_len];strcpy(dest, src.c_str().data());int compare_result = strcmp(src.c_str().data(), dest_str);

常用库函数属于高危函数,因为它们可能导致内存泄漏或其他资源泄漏,需谨慎使用。

STL原理及实现

STL(标准模板库)提供六大组件:容器、算法、迭代器、仿函数、配接器和配置器。这些组件通过参数化和泛型机制实现灵活的数据处理。

容器

  • 序列式容器vectorlistdequestackqueuearray等,支持随机访问和连续存储。
  • 关联式容器setmapmultisetmultimaphash_sethash_map等,基于红黑树或散列表实现。

算法

STL提供常用算法,如sortfinderasesearch等,通过迭代器对容器操作,确保算法不直接操作容器数据。

迭代器

STL迭代器实现了随机访问、前进和回退操作,通过重载运算符实现对容器元素的操作。

仿函数

仿函数作为算法的策略,重载了operator(),用于执行特定操作,如比较、映射等。

配接器

配接器修饰容器、迭代器或仿函数接口,支持自定义容器行为,例如back_inserter用于将序列式容器转换为输入迭代器。

配置器

配置器负责动态内存分配和管理,实现内存池和分离内存分配策略。

STL的核心原理是将算法与容器通过迭代器隔离,支持灵活的数据操作和算法组合。

list和vector的区别

  • vector

    • 内存连续,支持快速随机访问。
    • 适用于需要高效随机存取且不关心插入和删除效率的情况。
  • list

    • 内存不连续,支持高效的插入和删除。
    • 适用于需要频繁插入和删除且不关心随机存取的情况。

虚函数的作用和实现原理

虚函数

虚函数是动态多态的实现方式,允许子类重写父类的函数,具备运行时多态性。虚函数的实现依赖于虚函数表(vtbl)和虚函数指针(vptr)。

虚函数实现原理

  • vtbl:存储类中虚函数的函数指针数组,每个子类有自己的vtbl。
  • vptr:每个对象指向其vtbl地址。
  • 纯虚函数:在基类中定义,子类必须重写实现。

纯虚函数

纯虚函数在基类中定义,子类必须重写。例如:

class Base {public:    virtual ~Base() = 0; // 纯虚析构函数    virtual void func() = 0; // 纯虚函数};

纯虚函数的目的是定义接口,确保子类提供实现。

虚函数的使用

虚函数适用于需要动态多态的场景,如多形态继承结构。构造函数不能是虚函数,因为无法创建子类对象时调用虚函数。

内存分配方式及其优缺点

  • 静态内存分配
    内存在编译时预先分配,存储区域固定,适用于全局变量和静态变量。
  • 栈内存分配
    在函数执行时动态分配,内存释放自动,适用于局部变量。
  • 堆内存分配
    动态分配,需手动释放,灵活性高但带内存泄漏风险。

智能指针的实现原理

智能指针通过引用计数管理对象生命周期,确保对象在不再被引用时自动释放。实现方法包括引用计数或共享指针技术。

引用计数

  • 创建对象时初始化计数器。
  • 拷贝操作增加计数器。
  • 赋值操作减少左侧计数器,增加右侧计数器。
  • 析构函数减少计数器,释放对象。

共享指针

  • 使用共享指针时,多个指针共享同一对象。
  • 适用于多个对象共享的情况。

overrideoverload的区别

override(重写)

  • 方法名、参数和返回值与父类函数完全一致。
  • 子类方法不能缩小父类方法的访问权限。
  • 子类方法不能抛出比父类更多的异常。
  • 存在于父类和子类之间。

overload(重载)

  • 方法的参数类型、个数或顺序与父类函数有至少一个不同。
  • 不能重载只有返回值不同的函数。
  • 存在于父类和子类、同一类中。

Linux内存管理机制

虚拟内存

Linux采用地址映射机制,将虚拟地址映射到物理地址。内核通过TLB(转换表)加速地址转换,使用分区、请求页、交换和共享内存等机制。

内存寻址方式

  • 连续分配:内核采用分区管理内存,减少碎片。
  • 请求页:程序请求内核分配物理页,使用空闲页或从swap中获取。
  • 交换机制:用于内核和用户空间之间交换内存。
  • 内存共享:允许多个进程共享物理内存。

进程和线程管理

进程是资源分配的基本单位,线程是任务调度的基本单位。进程间可以通过共享内存进行通信,线程间可以通过内存共享、管道、信号等方式通信。

进程间通信

  • 共享内存:通过shm_open创建共享内存段,多个进程可读写。
  • 管道:用于单向或双向通信,适合简单的I/O传输。
  • 消息队列:支持多个进程间的异步通信。

线程间通信

  • 内存共享:多个线程共享同一内存空间。
  • 互斥机制:确保多个线程访问同一内存时的同步。

动态链接和静态链接的区别

动态链接

  • 编译时不生成目标模块的代码和数据。
  • 运行时动态加载模块,使用共享库(DLL)。
  • 依赖于运行时环境,需要特定的ldlibc支持。

静态链接

  • 编译时将目标模块的代码和数据复制到调用者模块中。
  • 无需运行时环境支持,依赖于编译时的链接步骤。
  • 不支持代码的替换和更新。

五种I/O 模式

  • 阻塞I/O

    • 默认I/O模式,所有I/O操作阻塞。
    • 适用于传统的同步I/O应用。
  • 非阻塞I/O

    • 使用fcntlopen时的O_NONBLOCK标志。
    • I/O操作立即返回,无阻塞。
  • I/O多路复用

    • 使用selectpoll监控多个I/O描述符。
    • 适用于需要同时处理多个I/O事件的应用。
  • 信号驱动I/O

    • 使用SIGIO信号报告I/O事件。
    • 适用于需要及时响应I/O事件的应用。
  • 异步I/O

    • 使用aio函数进行异步I/O操作。
    • 适用于高效率I/O处理,减少用户线程等待时间。
  • socket服务端实现:select和epoll的区别

    select模型

    • 依赖于32位的文件描述符集合,最大并发数受限(默认为1024)。
    • 每次调用需线性扫描所有文件描述符,效率较低。
    • 内核拷贝文件描述符信息到用户空间。

    epoll模型

    • 不受文件描述符数量限制,支持大量文件描述符。
    • 高效率,内核维护文件描述符列表,减少内存拷贝。
    • 提供水平触发和边缘触发模式,性能更优。

    epoll的触发模式

    水平触发

    -通知进程所有就绪的文件描述符。

    • 适用于大量文件描述符且活跃度较低的场景。

    边缘触发

    • 只通知刚刚变为就绪状态的文件描述符。
    • 适用于活跃度高的场景,减少通知次数。

    TCP和UDP的区别

    TCP

    • 面向连接的、可靠的、字节流服务。
    • 需要三次握手建立连接,确保数据可靠传输。
    • 提供流量控制、拥塞控制和错误检测。

    UDP

    • 面向无连接的、不可靠的、数据报服务。
    • 数据传输不保证顺序或可靠性。
    • 传输速度快,适合实时应用。

    TCP和UDP选项

    TCP选项

    • SOCKET:设置socket选项。
    • connect:设置连接超时和防止连接重用。
    • send:设置发送缓冲区大小和数据传输大小。
    • close:设置等待时间和释放资源。

    UDP选项

    • SOCKET:设置socket类型和数据大小限制。
    • send:设置发送缓冲区大小和数据传输大小。
    • close:设置等待时间和释放资源。

    connect会阻塞,解决方法

    connect会阻塞

    • 使用socket时,connect操作会阻塞,等待连接建立。
    • 解决方法包括:
      • 使用AI_PASSIVE标志,允许非阻塞连接尝试。
      • 使用线程或异步I/O模型进行非阻塞连接。

    海量数据处理:Bitmap和BloomFilter

    BloomFilter

    BloomFilter是一种概率数据结构,用于估算元素出现概率。其核心思想是减少存储空间和查询时间,通过哈希函数和预期的冲突率设计。

    BloomFilter原理

    • 预期冲突率:P = (m/k)^r,其中m是输入数据数量,k是哈希表大小,r是基数。
    • 通过哈希函数将数据映射到哈希表中,计算冲突概率。
    • 温度降低冲突率的方法:增加哈希表大小、降低基数、使用双哈希函数。

    BloomFilter的优点:

    • 节省存储空间。
    • 减少查询时间。
    • 适用于大数据量和高查询频率场景。

    转载地址:http://tgev.baihongyu.com/

    你可能感兴趣的文章
    OneBlog Shiro 反序列化漏洞复现
    查看>>
    oneM2M
    查看>>
    one_day_one--mkdir
    查看>>
    ONI文件生成与读取
    查看>>
    Online PDF to PNG、JPEG、WEBP、 TXT - toolfk
    查看>>
    onlstm时间复杂度_CRF和LSTM 模型在序列标注上的优劣?
    查看>>
    onlyoffice新版5.1.2版解决中文汉字输入重复等问题
    查看>>
    onnx导出动态输入
    查看>>
    onnx导出动态输入
    查看>>
    onScrollStateChanged无效
    查看>>
    onTouchEvent构造器
    查看>>
    on_member_join 和删除不起作用.如何让它发挥作用?
    查看>>
    oobbs开发手记
    查看>>
    OOM怎么办,教你生成dump文件以及查看(IT枫斗者)
    查看>>
    OOP
    查看>>
    OOP之单例模式
    查看>>
    OOP向AOP思想的延伸
    查看>>
    OO第一次blog
    查看>>
    OO第四次博客作业
    查看>>
    OO面向对象编程:第三单元总结
    查看>>