C++高频知识点(二十八)
文章目录
- 136. 什么是拷贝控制?包括哪些内容?
- 拷贝构造函数
- 拷贝赋值运算符
- 析构函数
- 移动构造函数
- 移动赋值运算符
- 137. Socket网络编程你做过吗?说说建立TCPSocket的函数名是什么?和UDPSocket 的关键参数区别是什么?
- 建立 TCP Socket 的函数名
- 建立 UDP Socket 的函数名
- TCP 和 UDP 的关键参数区别
- 138. 大数据中找中位数,谈谈你的思路。
- 分桶思维
- 核心步骤
- 示例(体会一下整个思路):将数据分桶并定位中位数
- 139. 对称加密和非对称加密有什么区别?说出一种对称加密算法。
- 核心区别
- 实际应用
- 一种对称加密算法
- 140. STL 容器的 sort()使用了哪种排序算法?
- 快排实现代码
136. 什么是拷贝控制?包括哪些内容?
在 C++ 中,拷贝控制 是一组用于管理对象如何被拷贝、赋值和销毁的机制。拷贝控制的目的是确保对象的资源(如内存、文件句柄等)能够在对象拷贝或赋值时正确地被管理,防止出现资源泄漏或浅拷贝的问题。
拷贝构造函数
ClassName(const ClassName& other);
默认的赋值运算符执行的是 浅拷贝,即将一个对象的数据成员的值复制给另一个对象的对应成员。
在 obj3 = obj1; 执行时,obj3 的 data 成员会指向 obj1 的 data 内存,而在 obj3 析构时会尝试删除相同的内存,导致 双重删除(double delete),进而导致程序崩溃。
#include <iostream>class MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {std::cout << "Constructor: Allocated memory for value " << value << std::endl;}// 拷贝构造函数MyClass(const MyClass& other) {data = new int(*other.data); // 注意这里使用了深拷贝:分配新内存并复制值std::cout << "Copy Constructor: Copied value " << *other.data << std::endl;}// 析构函数~MyClass() {std::cout << "Destructor: Deleting value " << *data << std::endl;delete data; // 释放动态分配的内存}// 显示值void display() const {std::cout << "Value: " << *data << std::endl;}
};int main() {MyClass obj1(42); // 调用构造函数obj1.display();// 使用拷贝构造函数MyClass obj2 = obj1; // 调用拷贝构造函数obj2.display();// 修改 obj1 的值,验证深拷贝是否有效{MyClass obj3(99); // 创建一个新的对象obj3 = obj1; // 注意:这里是赋值操作,不是拷贝构造} // obj3析构return 0;
}//这里我说一个重点区分。就是要区分 拷贝构造 和 拷贝赋值,不然我们会傻傻分不清。
//拷贝构造函数用于新对象的初始化,即用一个已有的对象初始化另一个新创建的对象。强调这个新字。
//赋值运算符用于赋值操作,即当一个已有的对象将另一个已有对象的内容复制到自身时触发。强调“已有”。
拷贝赋值运算符
- 拷贝赋值运算符用于将一个对象的值赋给另一个已经存在的对象。它会在以下情况下被调用:
- 当使用 = 运算符将一个对象赋值给另一个对象时。
ClassName& operator=(const ClassName& other);
class MyClass {
private:int* data;
public:MyClass(int value) : data(new int(value)) {}// 拷贝赋值运算符MyClass& operator=(const MyClass& other) {if (this == &other) {return *this; // 自赋值检查}delete data; // 释放原有资源data = new int(*other.data); // 复制新数据return *this;}
};
析构函数
- 析构函数用于销毁对象,释放对象占用的资源。当对象生命周期结束时(如超出作用域时),析构函数会自动调用。
~ClassName();
class MyClass {
private:int* data;
public:MyClass(int value) : data(new int(value)) {}// 析构函数~MyClass() {delete data; // 释放资源}
};
移动构造函数
- 移动构造函数用于通过“偷取”资源(而非拷贝)来初始化一个新对象,从而避免不必要的资源复制。它在 C++11 引入,适用于需要高效移动的类(如 std::vector)。
ClassName(ClassName&& other) noexcept;
#include <iostream>
#include <utility> // std::moveclass MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {std::cout << "Constructor: Allocated memory for value " << value << std::endl;}// 移动构造函数MyClass(MyClass&& other) noexcept {data = other.data; // “偷取”资源other.data = nullptr; // 将原对象的指针置空,防止析构时重复释放std::cout << "Move Constructor: Transferred ownership" << std::endl;}// 拷贝构造函数MyClass(const MyClass& other) {data = new int(*other.data); // 深拷贝std::cout << "Copy Constructor: Copied value " << *data << std::endl;}// 析构函数~MyClass() {if (data) {std::cout << "Destructor: Deleting value " << *data << std::endl;delete data; // 释放动态内存} else {std::cout << "Destructor: No resource to delete" << std::endl;}}// 显示值void display() const {if (data) {std::cout << "Value: " << *data << std::endl;} else {std::cout << "No data available" << std::endl;}}
};int main() {// 创建对象MyClass obj1(42); // 调用普通构造函数obj1.display();// 使用移动构造函数MyClass obj2(std::move(obj1)); // 调用移动构造函数obj2.display();obj1.display(); // obj1 的资源已被转移,变为空// 创建一个新对象并使用拷贝构造函数MyClass obj3 = obj2; // 调用拷贝构造函数obj3.display();return 0;
}
移动赋值运算符
- 移动赋值运算符与移动构造函数类似,也是通过“偷取”资源来避免不必要的资源复制。它用于将一个对象的资源转移到另一个对象,并释放目标对象原本的资源。
ClassName& operator=(ClassName&& other) noexcept;
#include <iostream>
#include <utility> // std::moveclass MyClass {
private:int* data;public:// 构造函数MyClass(int value) : data(new int(value)) {std::cout << "Constructor: Allocated memory for value " << value << std::endl;}// 拷贝构造函数MyClass(const MyClass& other) : data(new int(*other.data)) {std::cout << "Copy Constructor: Copied value " << *data << std::endl;}// 移动赋值运算符MyClass& operator=(MyClass&& other) noexcept {if (this != &other) {delete data; // 释放现有资源data = other.data; // "偷取"资源other.data = nullptr; // 将源对象的数据指针置为 nullptrstd::cout << "Move Assignment Operator: Transferred ownership" << std::endl;}return *this;}// 析构函数~MyClass() {if (data) {std::cout << "Destructor: Deleting value " << *data << std::endl;delete data; // 释放动态分配的内存} else {std::cout << "Destructor: No resource to delete" << std::endl;}}// 显示值void display() const {if (data) {std::cout << "Value: " << *data << std::endl;} else {std::cout << "No data available" << std::endl;}}
};int main() {// 创建对象MyClass obj1(42); // 调用普通构造函数obj1.display();MyClass obj2(84); // 调用普通构造函数obj2.display();// 使用移动赋值运算符obj2 = std::move(obj1); // 调用移动赋值运算符obj2.display();obj1.display(); // obj1 的资源已被转移,变为空return 0;
}
137. Socket网络编程你做过吗?说说建立TCPSocket的函数名是什么?和UDPSocket 的关键参数区别是什么?
Socket 网络编程 是服务器后端开发的基础之一。
建立 TCP Socket 的函数名
TCP Socket 是基于连接的流协议,提供可靠的数据传输。建立 TCP Socket 的常用函数及其作用如下:
建立 UDP Socket 的函数名
UDP Socket 是无连接的、基于数据报的协议,不保证可靠性,但传输效率高。建立 UDP Socket 的常用函数如下:
TCP 和 UDP 的关键参数区别
138. 大数据中找中位数,谈谈你的思路。
分桶思维
分桶/直方图方法主要通过将数据分成多个区间(或桶),根据桶中的元素数量来快速定位中位数。其核心思想是利用数据的分布特性,减少每次查找中位数的计算复杂度。
大概思路:
在大数据或流式数据的场景中,直接对所有数据排序可能不现实。分桶法通过将数据映射到多个“桶”(区间)中,每个桶表示一定范围的数据。通过统计各桶中元素的数量,快速找到包含中位数的桶,再从该桶中精确地确定中位数。
核心步骤
示例(体会一下整个思路):将数据分桶并定位中位数
139. 对称加密和非对称加密有什么区别?说出一种对称加密算法。
核心区别
实际应用
- 对称加密:用于大数据加密传输,因为速度快,比如 HTTPS 通信中的会话数据加密。
- 非对称加密:常用于密钥交换、数字签名,比如 HTTPS 中的密钥协商过程。
一种对称加密算法
140. STL 容器的 sort()使用了哪种排序算法?
在 C++ STL 中,std::sort() 函数使用了一种 混合排序算法,通常是 Introsort(内省排序)。
#include <iostream>
#include <vector>
#include <algorithm>int main() {std::vector<int> data = {10, 5, 8, 3, 7};std::sort(data.begin(), data.end()); // 调用 Introsortfor (const auto& num : data) {std::cout << num << " ";}return 0;
}
//理想情况
[10, 2, 8, 7, 1] -> 分区后 -> [2, 1] [8, 10, 7]
//最坏情况
[1, 2, 3, 4, 5] -> 分区后 -> [] [2, 3, 4, 5]
快排实现代码
#include <bits/stdc++.h>using namespace std;int partition(vector<int>& v, int left, int right) {int pivot = v[left];while(left < right) {while(left < right && v[right] >= pivot) {--right;}if(left < right) {v[left] = v[right];}while(left < right && v[left] <= pivot) {++left;}if(left < right) {v[right] = v[left];}}v[left] = pivot;return left;
}void quickSort(vector<int>& v, int left, int right) {if(left < right) {int pos = partition(v, left, right);quickSort(v, left, pos - 1);quickSort(v, pos + 1, right);}
}int main() {vector<int> a = {15, 3, 6, 0, 1};quickSort(a, 0, 4);for(const int & num: a) {cout<< num<< " ";}cout << endl;return 0;
}
之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!