问题

  1. 三种多态的实现方式及其区别
  2. STL 容器在 for 循环中使用 erase 删除元素会导致什么问题?
  3. 什么是Perfec t Forwarding?为什么要使用它,它解决了什么问题?写一下
  4. 完美转发和移动语义的实践场景
  5. 虚函数表的存储位置和内存结构
  6. 单继承、多继承、虚继承的vptr是怎样的?对应的C++内存模型是怎样的
  7. 虚函数能否是模板函数?为什么?
  8. 析构函数声明为虚函数的原因是什么?
  9. C++类默认生成的成员函数有哪些?
  10. 左值和右值的区别与应用场景
  11. Name Mangling的作用及其带来的兼容性问题
  12. 动态库和静态库的优缺点对比
  13. 什么是智能指针?什么是RAII?既然如此,全部用栈区不就可以了,为什么要堆区? 或者全部用堆区可以了,为什么要栈区?
  14. vector有什么缺点,为什么要有pvector?或者问移动构造的适用场景(如gapbs)
  15. 【打卡题】const与指针和引用
  16. 【打卡题】宏定义 defineconst 常量
  17. new 和malloc的区别
  18. atomic原子操作为什么比读写锁更快?
  19. vector和dequeue的区别,为什么遍历vector的效率更高。

参考回答

  1. 三种多态的实现方式及其区别

    静态多态和动态多态:函数重载、运算符重载、泛型编程与模板(特别的CRTP)(编译期多态);虚函数 动态多态

  2. STL 容器在 for 循环中使用 erase 删除元素会导致什么问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
std::vector<int> vec = {1, 2, 3, 4, 5};

// 错误方式:迭代器失效、变成野指针
for (auto it = vec.begin(); it != vec.end(); ++it) {
if (*it % 2 == 0) {
vec.erase(it); // it 失效,后续 ++it 未定义行为
}
}

// 正确方式1:利用返回值
for (auto it = vec.begin(); it != vec.end(); ) {
if (*it % 2 == 0) {
it = vec.erase(it); // erase返回下一个有效迭代器
} else {
++it;
}
}

// 正确方式2:remove-erase惯用法
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](int x) { return x % 2 == 0; }),
vec.end());
  1. 什么是Perfec t Forwarding?为什么要使用它,它解决了什么问题?写一下
    在函数模板中,保持参数的原有类型和特性(const)进行转发。没有完美转发时,泛型编程会遇到参数类别丢失的问题。传入右值时,T会被推导成非右值,const属性也会消失;
1
2
3
4
5
6
7
template<typename T>
void wrapper(T arg)
{
callee(arg);
callee(std::forward<T> (arg));
}

  1. 完美转发和移动语义的实践场景
    日志函数\ 装饰器模式、容器构造器
1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T>
void log_and_call(T arg){
std::cout<<"aaa";
call(std::forward<T> arg);
}

//比如我的项目中需要实现一个基于new的转发功能
template <typename T, typename... Args>
T* cxl_new(Args&&... args) {
void* raw = hmalloc(sizeof(T));
if (!raw) throw std::bad_alloc();
return new (raw) T(std::forward<Args>(args)...);
}
  1. 虚函数表的存储位置和内存结构
    vtable 只读数据段、vptr对象内部

  2. 单继承、多继承、虚继承的vptr是怎样的?对应的C++内存模型是怎样的

  3. 虚函数能否是模板函数?为什么?
    虚函数不能是模板函数。虚函数表要求在编译器固定布局,模板函数实例化在编译器按需生成。时机冲突

  4. 析构函数声明为虚函数的原因是什么?
    当一个派生类对象通过 基类指针 删除时,如果基类的析构函数 不是虚的,将只会调用基类析构函数,而派生类部分不会被析构,造成 资源泄漏未定义行为

  5. C++类默认生成的成员函数有哪些?
    默认构造、拷贝、析构、移动、拷贝赋值与移动赋值

  6. 左值和右值的区别与应用场景

  7. Name Mangling的作用及其带来的兼容性问题

  8. 动态库和静态库的优缺点对比

  9. 什么是智能指针?什么是RAII?既然如此,全部用栈区不就可以了,为什么要堆区? 或者全部用堆区可以了,为什么要栈区?
    堆适用 大小不确定,并且可以利用零散碎片,栈不行;栈适合函数,天生紧凑,堆不行;两者协作处理会使得内存更加紧凑高效。

    工厂模式的一个优点:唯一化管理,比如LLVM中的Type类型管理

  10. vector有什么缺点,为什么要有pvector?或者问移动构造的适用场景(如gapbs)

  11. 【打卡题】const与指针和引用

  12. 【打卡题】宏定义 defineconst 常量

  13. new 和malloc的区别

  14. atomic原子操作为什么比读写锁更快?(硬件指令)
    1.硬件指令实现
    atomic原子操作是硬件级别的,直接在CPU指令和缓存层完成,会通过特定的硬件指令直接锁CPU的缓存行和内存总线,确保其他核心无法访问同一块内存。

    而读写锁则是软件级别的,需要内核系统调用实现,基于互斥锁机制实现,线程无法获取锁时会通过系统调用将自己放入等待队列,涉及用户态内核态切换,导致比成本比硬件实现高出几个数量级。


本站由 Zane Jiang 使用 Stellar 1.33.1 主题创建,一款很棒的 Hexo 主题!

总访问 次 || 本页访问
总访客 人 || 本页访客