C/C++ 面试八股文

C++面试常见问题 - 知乎

智能指针: 

智能指针(Smart Pointers)是一种用于管理动态内存的数据结构,通常用于C++和某些其他编程语言中。它们提供了更安全和方便的内存管理方式,帮助减少内存泄漏和悬垂指针等问题。智能指针是与RAII(资源获取即初始化)编程原则紧密相关的,因此它们确保在离开作用域时自动释放分配的内存。

主要的智能指针类型包括:

  1. std::shared_ptr:共享指针,允许多个智能指针共享相同的资源。资源在最后一个引用离开作用域时释放。

  2. std::unique_ptr:唯一指针,确保只有一个指针可以访问分配的资源。资源在唯一指针离开作用域时释放。

  3. std::weak_ptr:弱指针,与shared_ptr一起使用,用于解决循环引用的问题。弱指针不增加引用计数,它只能用于监视资源的生存状态。

智能指针的好处包括:

  • 自动内存管理:它们负责在资源不再需要时自动释放内存,减少了内存泄漏的风险。

  • 减少悬垂指针:当资源被释放后,智能指针将确保不再引用它,从而避免了悬垂指针问题。

  • 简化代码:它们可以减少显式的内存管理操作,使代码更清晰和安全。

  • 支持多线程:某些智能指针类型(如std::shared_ptr)具有引用计数,可以用于多线程环境。

使用智能指针有助于提高C++程序的健壮性和可维护性。然而,开发者仍然需要小心避免循环引用,以确保资源的正确释放。

实现一个智能指针:

#include <iostream>template <typename T>
class SmartPointer {
private:T* ptr;public:// 构造函数SmartPointer(T* p = nullptr) : ptr(p) {}// 析构函数~SmartPointer() {delete ptr;  // 在析构函数中释放资源}// 拷贝构造函数SmartPointer(const SmartPointer<T>& other) {ptr = new T(*other.ptr);}// 赋值运算符SmartPointer<T>& operator=(const SmartPointer<T>& other) {if (this == &other) {return *this;}delete ptr;  // 释放当前资源ptr = new T(*other.ptr);return *this;}// 解引用操作符T& operator*() {return *ptr;}// 成员访问操作符T* operator->() {return ptr;}
};int main() {SmartPointer<int> sp1(new int(42));SmartPointer<int> sp2 = sp1; // 使用拷贝构造函数SmartPointer<int> sp3(new int(10));sp3 = sp2; // 使用赋值运算符std::cout << "Value from sp1: " << *sp1 << std::endl;std::cout << "Value from sp2: " << *sp2 << std::endl;std::cout << "Value from sp3: " << *sp3 << std::endl;return 0;
}

share_ptr是如何实现的

std::shared_ptr 是C++标准库中的智能指针,它允许多个std::shared_ptr共享相同的资源,并在资源不再需要时自动释放。std::shared_ptr的实现通常基于引用计数,它会记录资源被多少个std::shared_ptr共享。以下是std::shared_ptr的基本工作原理:

  1. 构造和拷贝构造:当您创建一个std::shared_ptr时,它将创建一个引用计数对象,该对象包含两部分信息:指向分配的资源的指针和一个引用计数。

  2. 引用计数:每当您拷贝一个std::shared_ptr(或将其作为参数传递给函数),引用计数会递增。当析构或赋值操作使引用计数为零时,资源会被释放。

  3. 资源释放:当std::shared_ptr的引用计数变为零,它将自动释放关联的资源。这是通过析构函数来实现的,当引用计数为零时,析构函数被调用,资源被释放。

  4. 复制和赋值std::shared_ptr支持复制和赋值操作,使多个std::shared_ptr可以共享相同的资源,而不会出现悬垂指针问题。当一个std::shared_ptr离开作用域或不再需要资源时,它的引用计数会减少,直到资源不再被引用。

  5. 循环引用std::shared_ptr存在循环引用的潜在问题。如果两个或多个std::shared_ptr相互引用,它们的引用计数将永远不会变为零,导致资源泄漏。为了解决这个问题,C++11引入了std::weak_ptr,允许弱引用资源,但不会增加引用计数,用于打破循环引用。

std::shared_ptr的实现会维护引用计数并确保在没有引用时释放资源。这是通过使用std::shared_ptr的析构函数来实现的,当最后一个std::shared_ptr离开作用域或不再需要资源时,析构函数被调用,资源得到释放。引用计数的维护是线程安全的,这使得std::shared_ptr适用于多线程环境。

实现一个完整的 shared_ptr 需要涉及引用计数、资源管理、拷贝构造、赋值运算符重载等复杂的细节。以下是一个非常基本的示例,展示了 shared_ptr 的基本思想,但不包括线程安全和其他重要功能。请注意,这只是教育目的的示例,实际使用时应使用C++标准库中的 std::shared_ptr

#include <iostream>template <typename T>
class SharedPtr {
public:// 构造函数SharedPtr(T* ptr) : data(ptr), ref_count(new int(1)) {}// 拷贝构造函数SharedPtr(const SharedPtr<T>& other) : data(other.data), ref_count(other.ref_count) {(*ref_count)++;}// 析构函数~SharedPtr() {if (--(*ref_count) == 0) {delete data;delete ref_count;}}// 赋值运算符SharedPtr<T>& operator=(const SharedPtr<T>& other) {if (this == &other) {return *this;}// 减少当前对象的引用计数if (--(*ref_count) == 0) {delete data;delete ref_count;}data = other.data;ref_count = other.ref_count;(*ref_count)++;return *this;}// 解引用操作符T& operator*() {return *data;}// 成员访问操作符T* operator->() {return data;}private:T* data;int* ref_count;
};int main() {SharedPtr<int> sp1(new int(42));SharedPtr<int> sp2 = sp1;SharedPtr<int> sp3(new int(10));sp3 = sp2;std::cout << "Value from sp1: " << *sp1 << std::endl;std::cout << "Value from sp2: " << *sp2 << std::endl;std::cout << "Value from sp3: " << *sp3 << std::endl;return 0;
}

这个示例演示了一个非线程安全的 SharedPtr 类,它能够跟踪引用计数并在引用计数减为零时释放资源。在实际应用中,您需要考虑线程安全、更复杂的功能,以及更多的边界情况,以确保正确和高效的资源管理。最好的选择是使用C++标准库中的 std::shared_ptr,因为它已经经过充分测试和优化。

 shared_ptr使用方法:

1. 构造函数std::shared_ptr 可以使用多种构造函数创建,其中包括从原始指针、另一个 std::shared_ptr、或者其他智能指针类型创建。

std::shared_ptr<int> sp1(new int(42)); // 使用原始指针创建
std::shared_ptr<int> sp2 = std::make_shared<int>(42); // 使用 make_shared 创建
std::shared_ptr<int> sp3 = sp1; // 使用拷贝构造函数创建

拷贝构造函数:用于创建一个新的 std::shared_ptr,共享相同的资源。

std::shared_ptr<int> sp1(new int(42));
std::shared_ptr<int> sp2 = sp1; // 使用拷贝构造函数

赋值操作符:用于将一个 std::shared_ptr 赋值给另一个,共享相同的资源。

std::shared_ptr<int> sp1(new int(42));
std::shared_ptr<int> sp2;
sp2 = sp1; // 使用赋值操作符

reset 方法:用于重置 std::shared_ptr,它可以释放资源并指向新的资源。

std::shared_ptr<int> sp1(new int(42));
sp1.reset(new int(10)); // 重置 shared_ptr,释放旧资源

use_count 方法:用于获取 std::shared_ptr 的引用计数。

std::shared_ptr<int> sp1(new int(42));
int count = sp1.use_count(); // 获取引用计数

get 方法:用于获取 std::shared_ptr 内部的原始指针。

std::shared_ptr<int> sp1(new int(42));
int* rawPtr = sp1.get(); // 获取原始指针

*operator 和 operator->**:允许通过 *-> 操作符来访问资源。

std::shared_ptr<int> sp1(new int(42));
int value = *sp1; // 解引用操作符
int* rawPtr = sp1.get();
int value2 = *rawPtr; // 也可以通过原始指针访问

operator bool:用于检查 std::shared_ptr 是否为空(未指向任何资源)。

std::shared_ptr<int> sp1;
if (!sp1) {// shared_ptr 为空
}

这些方法和操作符使 std::shared_ptr 可以方便地管理资源和共享资源的所有权,同时自动处理引用计数和资源释放。

C++ 中的构造函数有几种:

在C++中,构造函数有几种不同的类型,主要分为以下几类:

  1. 默认构造函数(Default Constructor)

    • 默认构造函数没有参数,用于创建对象的实例。
    • 如果您没有为类定义构造函数,编译器会为您自动生成一个默认构造函数,但如果您自定义了任何构造函数,编译器将不再提供默认构造函数。
  2. 参数化构造函数(Parameterized Constructor)

    • 参数化构造函数接受一个或多个参数,用于初始化对象的成员变量。
    • 它允许您在创建对象时传递参数,以自定义对象的初始化。
  3. 拷贝构造函数(Copy Constructor)

    • 拷贝构造函数接受同一类型的对象作为参数,用于创建一个新对象,新对象的值与原对象相同。
    • 它在对象复制时被调用,通常在对象传递给函数或通过赋值操作时使用。
  4. 移动构造函数(Move Constructor)(C++11及以后):

    • 移动构造函数用于将资源从一个对象“移动”到另一个对象,而不是进行复制。这提高了性能,特别是在处理动态分配内存等资源时。
  5. 复制构造函数和移动构造函数可以重载的版本

    • 复制构造函数和移动构造函数可以有多个版本,根据参数的不同来重载。例如,可以有一个接受常量引用和一个接受非常量引用的版本。
  6. 析构函数(Destructor)

    • 析构函数没有参数,用于对象生命周期结束时清理资源。通常用于释放动态分配的内存、关闭文件、释放锁等操作。
  7. 委托构造函数(Delegating Constructor)(C++11及以后):

    • 委托构造函数是一个构造函数调用另一个构造函数,以减少冗余代码。这允许您在一个构造函数中调用另一个构造函数来执行实际的初始化工作。

这些构造函数类型提供了不同的初始化和对象创建方式,根据您的需要,可以选择适合的构造函数类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/108440.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

framework通信机制—LiveData使用方法及原理

LiveData是一种可观察的数据存储器类。与常规的可观察类不同&#xff0c;LiveData 具有生命周期感知能力&#xff0c;意指它遵循其他应用组件&#xff08;如 activity、fragment 或 service&#xff09;的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应…

模型量化笔记--对称量化和非对称量化

1–量化映射 量化映射的通用公式为: r S ( q − Z ) r S(q - Z) rS(q−Z) 其中r表示量化前数据的真实值&#xff0c;S表示缩放因子&#xff0c;q表示量化后的数值&#xff0c;Z表示零点 2–非对称量化 非对称量化需要一个偏移量Z来完成零点的映射&#xff0c;即量化前的零…

Vite创建Vue项目后遇到的问题

Vite创建Vue项目后遇到的问题 前言问题问题一问题二问题三问题四 补充 前言 Vite 创建 Vue项目还算顺利&#xff0c;但创建后不是万事大吉&#xff0c;遇到了各种的问题。现在就自己遇到的问题做个总结。 问题 问题一 创建后&#xff0c;在未修改任何配置的前提下&#xff0c…

L2-024 部落

在一个社区里&#xff0c;每个人都有自己的小圈子&#xff0c;还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里&#xff0c;于是要请你统计一下&#xff0c;在一个给定社区中&#xff0c;到底有多少个互不相交的部落&#xff1f;并且检查任意两个人是否属…

pg嵌套子查询

1.概念 查询里面还有查询 进阶版&#xff1a;关联子查询 2.相关运算符补充 in/all/any all&#xff1a;表中的所有内容遍历一边&#xff0c;等价与max some/any&#xff1a;表中任何一个&#xff0c;等价与min

汉得欧洲x甄知科技 | 携手共拓全球化布局,助力出海中企数智化发展

HAND Europe 荣幸获得华为云颁发的 GrowCloud 合作伙伴奖项&#xff0c;进一步巩固了其在企业数字化领域的重要地位。于 2023 年 10 月 5 日&#xff0c;HAND Europe 参加了华为云荷比卢峰会&#xff0c;并因其在全球拓展方面的杰出贡献而荣获 GrowCloud 合作伙伴奖项的认可。 …

C++新经典 | C++ 查漏补缺(内存)

目录 一、new和delete 1.new类对象时&#xff0c;括号问题 2.new做了什么事 3.delete做了什么事 4.new与malloc的区别 5.delete与free的区别 二、分配及释放内存 三、重载operator new和operator delete操作符 1.重载类中的operator new和operator delete操作符 &…

vue+element实现电商商城礼品代发网,商品、订单管理

一、项目效果图 1.首页 2.登录 版本2&#xff1a; 3.注册 4.找回密码 5.立即下单 6.商品详情 7.个人中心-工作台 8.个人中心-订单列表 9.订单中心-包裹列表 10.个人中心-工单管理 11.我的钱包 12.实名认证 13.升级vip 14.个人中心-推广赚钱 二、关键源码 1.路由配置 impor…

【机器学习】PyTorch-MNIST-手写字识别

文章目录 前言完成效果一、下载数据集手动下载代码下载MNIST数据集&#xff1a; 二、 展示图片三、DataLoader数据加载器四、搭建神经网络五、 训练和测试第一次运行&#xff1a; 六、优化模型第二次优化后运行&#xff1a; 七、完整代码八、手写板实现输入识别功能 前言 注意…

vue重修【005】自定义路由、插槽

文章目录 版权声明自定义指令指令初识指令中配置项指令语法指令值v-loading指令的封装分析实现 插槽默认插槽插槽默认值具名插槽作用域插槽使用步骤完整案例 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程…

如何快速定位BUG?BUG定位技巧及测试人员定位的N板斧

很多测试人员可能会说&#xff0c;我的职责就是找到bug&#xff0c;至于找原因并修复&#xff0c;那是开发的事情&#xff0c;关我什么事&#xff1f; 好&#xff0c;我的回答是&#xff0c;如果您只想做一个测试人员最基本最本分的事情&#xff0c;那么可以这么想。但是&#…

微信批量发朋友圈,多个号同步

近年来&#xff0c;随着数字营销的飞速发展&#xff0c;越来越多的企业开始将客户引至微信&#xff0c;并通过群发广告和发布朋友圈等方式进行产品推广&#xff0c;以实现高效率、低成本和良好的转化效果。随着号多起来了&#xff0c;朋友圈推广工作变得愈发繁琐&#xff0c;需…

Vue3 + Nodejs 实战 ,文件上传项目--实现图片上传

目录 技术栈 1. 项目搭建前期工作(不算太详细) 前端 后端 2.配置基本的路由和静态页面 3.完成图片上传的页面&#xff08;imageUp&#xff09; 静态页面搭建 上传图片的接口 js逻辑 4.编写上传图片的接口 5.测试效果 结语 博客主页&#xff1a;専心_前端,javascript,mys…

TiDB 7.4 发版:正式兼容 MySQL 8.0

MySQL 是全球最受欢迎的开源数据库&#xff0c;长期位于 DB-Engines Ranking 排行榜第二名&#xff0c;在世界范围内拥有数量庞大的企业用户和开发者。然而&#xff0c;随着时间的推移&#xff0c;MySQL 用户正面临新挑战。Oracle 官宣将在 2023 年 10 月终止 MySQL 5.7 版本的…

基于Qt HTTP应用程序项目案例

文章目录 主项目入口项目子头文件httpwindow.hhttpwindow.h源文件httpwindow.cppui文件效果演示主项目入口 main函数创建对象空间,确认窗口的大小和坐标。 #include <QApplication> #include <QDir> #include

2023,简历石沉大海?软件测试岗位真的已经饱和了....

各大互联网公司的接连裁员&#xff0c;政策限制的行业接连消失&#xff0c;让今年的求职雪上加霜&#xff0c;想躺平却没有资本&#xff0c;还有人说软件测试岗位饱和了&#xff0c;对此很多求职者深信不疑&#xff0c;因为投出去的简历回复的越来越少了。 另一面企业招人真的…

【halcon】halcon轮廓总结之select_contours_xld

前言 select_contours_xld 我认为是一个非常常用且实用的算子&#xff0c;用于对轮廓进行筛选。 简介 这段文档描述了一个名为"SelectContoursXld"的操作&#xff0c;用于根据不同特征选择XLD&#xff08;XLD是一种图像数据表示形式&#xff0c;表示轮廓线&#x…

竞赛 深度学习+python+opencv实现动物识别 - 图像识别

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

Golang学习:基础知识篇(二)—— 数组及切片

Golang学习&#xff1a;基础知识篇&#xff08;二&#xff09;—— 数组及切片 前言什么是Golang&#xff1f;Go语言的基础语法数组声明数组初始化数组访问数组知识点补充 切片定义切片切片初始化len() 和 cap() 函数空(nil)切片切片截取append() 和 copy() 函数知识点补充 前言…

ubuntu20.04安装FTP服务

安装 sudo apt-get install vsftpd# 设置开机启动并启动ftp服务 systemctl enable vsftpd systemctl start vsftpd#查看其运行状态 systemctl status vsftpd #重启服务 systemctl restart vsftpdftp用户 sudo useradd -d /home/ftp/ftptest -m ftptest sudo passwd ftptest…