当前位置: 首页 > news >正文

【面经】C++八股文(地平线C++一面)

一、C++11的新特性都有哪些?

1.1 自动类型推断 (auto)

auto 关键字允许编译器自动推断变量的类型,从而简化代码的书写。

auto num = 5;        // int
auto pi = 3.14;     // double
auto str = "Hello"; // const char*

1.2 范围 for 循环

范围 for 循环可以简化容器(如数组和 STL 容器)的遍历。

std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto& i : vec) {std::cout << i << " "; // 输出 1 2 3 4 5
}

1.3 Lambda 表达式和函数闭包

Lambda 表达式提供了一种简洁的方式来定义匿名函数,并允许捕获外部变量。

int x = 10;
auto lambda = [x](int y) { return x + y; };
std::cout << lambda(5); // 输出 15

1.4 右值引用和移动语义

右值引用允许对临时对象进行高效的资源管理,移动语义使得资源的转移比复制更高效。

#include <utility>class MyClass {
public:MyClass() { /* 资源分配 */ }MyClass(MyClass&& other) { /* 资源转移 */ }
};MyClass createMyClass() {return MyClass(); // 返回一个右值
}MyClass obj = createMyClass(); // 通过移动构造

1.5 可变参数模板

可变参数模板允许函数接受任意数量的参数。

template<typename... Args>
void printAll(Args... args) {(std::cout << ... << args) << std::endl; // C++17 折叠表达式
}
printAll(1, 2, 3.5, "Hello"); // 输出: 1 2 3.5 Hello

1.6 初始化列表

初始化列表提供了一种更方便的方式来初始化容器和自定义类型。

std::vector<int> vec = {1, 2, 3, 4}; // 列表初始化
std::array<int, 3> arr = {1, 2, 3};   // std::array 初始化

1.7  强类型枚举

强类型枚举(enum class)提供了更强的类型安全性和作用域。

enum class Color { Red, Green, Blue };
Color c = Color::Red;
// c = 1; // 错误,不能隐式转换

1.8 智能指针如 std::unique_ptr 和 std::shared_ptr

智能指针帮助管理动态分配的内存,避免内存泄漏。

#include <memory>std::unique_ptr<int> p1 = std::make_unique<int>(5); // 独占型智能指针
std::shared_ptr<int> p2 = std::make_shared<int>(10); // 共享型智能指针

1.9 空指针关键字 (nullptr)

nullptr 是一个类型安全的空指针常量,取代了 NULL

int* p = nullptr; // p 是一个空指针

1.10 线程库支持

C++11 引入了 <thread> 头文件,使得多线程编程变得更加简单。

#include <thread>void threadFunction() {std::cout << "Hello from thread!" << std::endl;
}std::thread t(threadFunction);
t.join(); // 等待线程结束

1.11 新容器如 std::array 和 std::unordered_map

C++11 引入了一些新的标准容器。

  • std::array 是一个固定大小的数组,可以在编译时确定大小。
  • std::unordered_map 是一个基于哈希表的关联容器,提供常量时间复杂度的插入和查找。
#include <array>
#include <unordered_map>std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::unordered_map<std::string, int> umap = {{"one", 1}, {"two", 2}};

这些特性极大地增强了 C++ 的功能和可用性,使得编写现代 C++ 代码更加简洁、易于维护和高效。

二、了解什么设计模式?单例了解吗?


单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实
例。

在C++中实现单例模式通常需要以下步骤:

私有化构造函数和析构函数:这样可以防止外部代码直接创建或销毁该类的实例。

提供一个私有的静态指针变量:该指针用于存储唯一实例的地址。

提供一个公共的静态方法:这个方法用于返回唯一实例,并确保实例在第一次调用时被创建。

#include <iostream>
#include <mutex>class Singleton {
private:// 私有构造函数Singleton() {std::cout << "Singleton instance created!" << std::endl;}// 私有析构函数~Singleton() {std::cout << "Singleton instance destroyed!" << std::endl;}// 私有静态指针,指向唯一实例static Singleton* instance;static std::mutex mutex_; // 线程安全的互斥锁public:// 禁止拷贝构造和赋值Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 公共静态方法获取唯一实例static Singleton* getInstance() {if (instance == nullptr) {std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全if (instance == nullptr) {instance = new Singleton();}}return instance;}
};// 初始化静态指针
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;int main() {Singleton* singleton1 = Singleton::getInstance();Singleton* singleton2 = Singleton::getInstance();// 验证两者是同一个实例if (singleton1 == singleton2) {std::cout << "Both are the same instance." << std::endl;}return 0;
}

三、TCP和UDP的区别?

3.1 连接

  • TCP(传输控制协议)

    • TCP 是面向连接的协议,这意味着在实际数据传输之前,必须先建立一个连接。这是通过三次握手(Three-Way Handshake)完成的,确保双方都准备好进行通信。
    • 三次握手的过程如下:
      1. 客户端发送一个 SYN(同步)包到服务器。
      2. 服务器回应一个 SYN-ACK(同步-确认)包。
      3. 客户端再发送一个 ACK(确认)包来确认连接建立。
  • UDP(用户数据报协议)

    • UDP 是无连接的协议,发送方和接收方之间不需要建立连接。数据可以立即发送,适合需要快速传输且对连接不敏感的应用。

3.2 可靠性

  • TCP

    • TCP 提供可靠的数据传输,确保数据的完整性和按顺序到达。它使用序列号来跟踪每个字节的发送和接收,采用重传机制来处理丢失的数据包,并通过校验和来检测数据错误。
  • UDP

    • UDP 不提供可靠性保证,数据包可能会丢失、重复或乱序到达。由于没有重传机制和流控制,UDP 适用于对实时性要求高的应用,比如视频会议、在线游戏等。

3.3 速度

  • TCP

    • 因为 TCP 需要进行连接建立、数据确认、错误检测和重传等操作,所以相对较慢。它适合需要高可靠性的数据传输,像文件传输、电子邮件等。
  • UDP

    • UDP 传输速度较快,因为它没有连接建立过程和确认机制,适用于速度要求高且可以容忍数据丢失的场景,例如 DNS 查询、实时视频和音频传输。

3.4 数据流

  • TCP

    • TCP 是面向字节流的协议,它将数据视为一个连续的字节流。应用程序发送的数据会被分割成多个数据包,接收方再将这些数据包重新组装成完整的数据流。
  • UDP

    • UDP 是面向消息的协议,每个数据包(称为数据报)都是独立的。数据报的大小有限,UDP 不会将多个数据报组合成一个流,需要应用程序自己处理消息的边界。

 四、左值和右值引用?

左值引用是对可寻址的、可重复使用的对象(左值)的引用。它使用传统的单个&符号

右值引用是对临时对象(右值)的引用,使用双&&符号。右值引用允许实现移动语义和完美转发,它可以将资源从一个(临时的)对象转移到另一个对象,提高效率,避免不必要的复制。

五、能说说static关键字吗?

5.1 static关键字有几个用途:

1. 当在类的数据成员前使用 static 时,表示该成员属于类本身,而不是任何特定的实例。所有实例共享这一成员。

class MyClass {
public:static int count; // 静态数据成员MyClass() {count++; // 每创建一个实例,count 增加}
};// 静态成员定义和初始化
int MyClass::count = 0;int main() {MyClass obj1;MyClass obj2;std::cout << MyClass::count; // 输出 2,表明创建了两个实例return 0;
}


2.当在类的成员函数前使用 static 时,可以在不创建类实例的情况下直接调用该函数。这通常用于那些不依赖于类的实例的功能。

class MyClass {
public:static void display() {std::cout << "Hello from static function!" << std::endl;}
};int main() {MyClass::display(); // 直接调用静态成员函数return 0;
}


3.在函数内部使用static定义局部变量,使得该变量的值在函数调用间持久存在,而不是每次调
用时都重新创建。

#include <iostream>void counter() {static int count = 0; // 静态局部变量count++;std::cout << "Count: " << count << std::endl; // 每次调用显示当前计数
}int main() {counter(); // 输出 Count: 1counter(); // 输出 Count: 2counter(); // 输出 Count: 3return 0;
}


4.在文件、函数或区域前使用static,可以限制该变量或函数的链接可见性,令其只在定义它的
文件或作用域内部可见。

// 文件 A.cpp
static void helper() {std::cout << "This is a static function." << std::endl;
}void publicFunction() {helper(); // 可以调用
}// 文件 B.cpp
// void anotherFunction() {
//     helper(); // 错误,无法访问 A.cpp 中的 static 函数
// }

2. static 关键字在 C++ 中具有多种用途:

用于定义类的静态数据成员和静态成员函数。

用于保持局部变量在函数调用之间的状态。

用于限制变量和函数的可见性,确保它们仅在定义它们的文件或作用域内可见。

六、进程间通信的方式有哪些?线程间的数据交互?

6.1 进程间通信方式包括:

1.管道(Pipes)

2.命名管道(FIFO)

3.信号(Signals】

4.消息队列(Message Queues)

5.共享内存(Shared Memory)

6.信号量(Semaphores)

7.套接字(Sockets)】

8.内存映射文件(Memory-mapped files)

6.2 线程间的数据交互可以通过:

1.锁(如互斥锁Mutex)

2.条件变量(Condition Variables)

3.信号量(Semaphores)

4.线程局部存储(Thread-local Storage,TLS)

5.全局变量(通过使用同步机制以避免并发访问问题)

七、用过什么容器,map和unordered_map了解吗?vector的底层原理是什么?vector的扩容机制了解多少?map的底层原理能说说吗?

7.1 std::map

  • 底层实现std::map 是基于红黑树实现的,这是一种自平衡的二叉搜索树。
  • 特性
    • 元素根据键值自动排序。
    • 插入、删除和查找操作的时间复杂度为 O(log n)。

7.2 std::unordered_map

  • 底层实现std::unordered_map 采用哈希表作为底层实现。
  • 特性
    • 元素不会自动排序,存储顺序取决于哈希值。
    • 平均情况下,插入、删除和查找操作的时间复杂度为 O(1),但在最坏情况下(如哈希冲突严重时)可能会达到 O(n)。

7.3 std::vector

1. 底层原理

  • std::vector 是基于动态数组实现的,允许随机访问。
  • 它在连续的内存空间中存储元素,这使得访问速度非常快(O(1) 时间复杂度)。

2. 扩容机制

  • 当向 vector 添加元素超过当前容量时,会创建一个更大的动态数组(通常是当前容量的两倍),并将现有元素复制到新数组中,然后释放旧数组的内存。这种扩容策略有助于减少频繁内存分配的开销,从而提高性能。

7.4 std::map 的底层原理

  • std::map 是基于红黑树实现的,自平衡的特性帮助确保在最坏情况下也能保持 O(log n) 的时间复杂度。
  • 红黑树的特点包括:
    • 每个节点都有一个颜色(红色或黑色),并遵循特定规则以确保树的高度保持在对数级别。
    • 通过键值对自动排序,保证了数据结构的稳定性和高效操作。

 八、std::move??

std::move 是 C++11 中引入的一个标准库函数,其主要作用是将其参数转换为右值引用。这样做可以让程序利用移动语义,以高效地转移资源而不进行不必要的复制。

九、C++转型操作符?

9.1 static_cast

  • 用途用于基本数据类型转换和安全的向上转型。
  • 特点
    • 可以转换内置类型(如 int 到 float)。
    • 支持向上转型,即将派生类的对象或指针转换为基类。
    • 不能进行不安全的向下转型,如果需要向下转型,则需要使用 dynamic_cast

9.2 dynamic_cast

  • 用途用于类层次结构中的安全向下转型及运行时类型检查。
  • 特点
    • 需要 RTTI(运行时类型信息)支持。
    • 当进行向下转型时,可以确保转换的安全性。如果转换不成功,dynamic_cast 会返回 nullptr(对于指针类型)或抛出异常(对于引用类型)。
    • 常用于多态类,确保在运行时检查对象的真实类型。

 9.3 const_cast

  • 用途用于移除对象的 const 或 volatile 属性。
  • 特点
    • 允许对常量对象进行修改(需谨慎使用,因为这可能导致未定义行为)。
    • 主要用于在需要非常量引用或指针的情况下,如与某些 API 交互时。

9.4 reinterpret_cast

  • 用途用于低级别的类型转换,重新解释底层位模式。
  • 特点
    • 可以将一个指针转换为任何其他类型的指针。
    • 这种转换是非常不安全的,因为它不进行任何类型检查,可能导致未定义行为。
    • 通常用于特定的低级编程场景,如系统编程和硬件交互。

 十、智能指针了解吗?weak_ptr?

智能指针是 C++11 引入的一个重要概念,主要用于管理动态分配的内存,避免手动管理内存带来的问题。std::weak_ptr 是智能指针中的一种,专门用于解决循环引用的问题

10.1 std::weak_ptr 详细说明

  1. 定义

    std::weak_ptr 是一种智能指针,用于观察由 std::shared_ptr 管理的对象。它并不拥有该对象,因此不会增加对象的引用计数。
  2. 目的

    主要用于解决循环引用问题。例如,当两个对象相互持有 shared_ptr,如果使用 shared_ptr,这会导致引用计数永远不为零,从而造成内存泄漏。使用 weak_ptr 可以避免这种情况,因为它不会影响引用计数。
  3. 使用方式

    当需要访问 weak_ptr 指向的对象时,可以调用 lock() 方法,该方法会尝试返回一个 shared_ptr

                 (1)如果原始的 shared_ptr 仍然存在,lock() 将返回一个有效的 shared_ptr,并增加引用计数。

                (2)如果原始的 shared_ptr 已经被销毁,lock() 将返回一个空的 shared_ptr

10.2 示例代码:

#include <iostream>
#include <memory>class Node {
public:Node(int value) : value(value) {std::cout << "Node " << value << " created.\n";}~Node() {std::cout << "Node " << value << " destroyed.\n";}int value;std::shared_ptr<Node> next;
};int main() {std::shared_ptr<Node> node1 = std::make_shared<Node>(1);std::shared_ptr<Node> node2 = std::make_shared<Node>(2);// 产生循环引用node1->next = node2;node2->next = node1;// 使用 weak_ptr 解决循环引用std::weak_ptr<Node> weakNode1 = node1;std::weak_ptr<Node> weakNode2 = node2;// 检查 weak_ptr 是否有效if (auto shared1 = weakNode1.lock()) {std::cout << "Weak pointer is valid, value: " << shared1->value << "\n";}if (auto shared2 = weakNode2.lock()) {std::cout << "Weak pointer is valid, value: " << shared2->value << "\n";}// 让 node1 和 node2 超出作用域node1.reset();node2.reset(); // 这时 node1 和 node2 被销毁// 检查 weak_ptr 是否有效if (auto shared1 = weakNode1.lock()) {std::cout << "Weak pointer is valid, value: " << shared1->value << "\n";} else {std::cout << "Weak pointer is no longer valid.\n";}return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • WebGL-编译报错,如何定位sendfile报错位置
  • java事务回滚原理 Java事务回滚的实现及流程
  • AFAC2024-基于保险条款的问答 比赛日记 llamafactory qwen npu 910B1
  • 微软CrowdStrike驱动蓝屏以及内核签名
  • 谷粒商城实战笔记-45-商品服务-API-三级分类-查询-递归树形结构数据获取
  • Lua 语法学习笔记
  • 【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决
  • 压缩包方式windows安装mysql
  • ORBSLAM3 ORB_SLAM3 Ubuntu20.04 ROS Noetic 虚拟机镜像 下载
  • 【漏洞复现】Netgear WN604 downloadFile.php 信息泄露漏洞(CVE-2024-6646)
  • CCF-CSP认证考试 202406-2 矩阵重塑(其二) 100分题解
  • 如何查看jvm资源占用情况
  • JavaScript(11)——对象
  • SSD基本架构与工作原理
  • MongoDB教程(十一):MongoDB关系管理与文档关联
  • 【347天】每日项目总结系列085(2018.01.18)
  • go append函数以及写入
  • IndexedDB
  • JavaWeb(学习笔记二)
  • LeetCode29.两数相除 JavaScript
  • Promise面试题2实现异步串行执行
  • Spring声明式事务管理之一:五大属性分析
  • vue学习系列(二)vue-cli
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 深度学习在携程攻略社区的应用
  • 时间复杂度与空间复杂度分析
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • ​如何防止网络攻击?
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • ​用户画像从0到100的构建思路
  • #微信小程序(布局、渲染层基础知识)
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (9)目标检测_SSD的原理
  • (JS基础)String 类型
  • (LeetCode 49)Anagrams
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)pulsar安装在独立的docker中,python测试
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)Android学习笔记 --- android任务栈和启动模式
  • .bashrc在哪里,alias妙用
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .Net 6.0--通用帮助类--FileHelper
  • .net SqlSugarHelper
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .NET学习教程二——.net基础定义+VS常用设置
  • @Autowired和@Resource的区别