#C++进阶
文章平均质量分 91
介绍C++的比较深入的知识,比如模板、C++标准库的源码分析等等
流星雨爱编程
记录工作的日常,心得体会
展开
-
史上最全C/C++面试题集锦
select、poll、epoll都是IO多路复用的一种机制,可以监视多个文件描述符,一旦某个文件描述符进入读或写就绪状态,就能够通知系统进行相应的读写操作。Select优点:可移植性好,因为在某些Unix系统中并不支持poll和epoll对于超时时间提供了更好的精度:微妙,而poll和epoll都是毫秒级Select缺点:支持监听的文件描述符fd的数量有限制,最大数量默认是1024个。原创 2024-05-20 22:58:51 · 253 阅读 · 7 评论 -
C++之std::bitset使用精讲(全)
bitset满足可复制构造 (CopyConstructible)及可复制赋值 (CopyAssignable)的要求。下面是// 创建一个长度为 N 的 bitset,所有位都被初始化为 0// 使用二进制整数 value 初始化一个长度为 N 的 bitset// 使用二进制字符串 string 初始化一个长度为 N 的 bitset//用整个字符串来初始化bitset// 使用另一个 bitset 初始化一个长度为 N 的 bitset。原创 2024-05-16 22:58:23 · 788 阅读 · 15 评论 -
手撕代码:实现自己的unique_ptr
通过实现自定义的UniquePtr,我们不仅学习了智能指针的内部机制,还掌握了如何管理动态分配的内存资源,以及如何设计可重用和可扩展的C++代码。当然,实际生产中的智能指针实现会更加复杂,需要考虑更多的边界情况和性能优化。现在,我们的UniquePtr类已经具备了基本的智能指针功能,能够自动管理内存,并且支持移动语义和自定义删除器。这个实现虽然简单,但足以展示智能指针的核心思想和工作原理。在实际项目中,建议使用标准库提供的std::unique_ptr,因为它已经原创 2024-05-13 20:00:07 · 250 阅读 · 1 评论 -
std::ref和std::cref的使用和原理分析
std::reference_wrapper是一个模板类,用于包装引用,使其能够在容器中存储或以引用的形式传递。它提供类似引用的语法,并且可以与标准容器一起使用,因为容器无法直接存储引用。其实使用std::ref时,后台真正起作用的关键类是std::reference_wrapper,它才是真正包装引用的类。#if!原创 2024-05-12 12:49:06 · 853 阅读 · 0 评论 -
C++中的std::bind深入剖析
std::bind在 C++11 中引入,提供了一种将可调用对象(如函数、成员函数、函数对象等)与参数进行绑定的方式。然而,随着 C++ 的发展,尤其是 C++11 之后的版本,std::bind的使用逐渐受到了一些限制,因为 lambda 表达式提供了更加灵活和直观的方式来实现类似的功能。以下是std::bind优点:灵活性std::bind可以绑定函数、成员函数、函数对象等的参数,提供了一种灵活的方式来创建新的可调用对象。与结合使用std::bind创建的可调用对象可以很容易地赋值给。原创 2024-05-09 23:31:00 · 1434 阅读 · 15 评论 -
C++之std::tuple(一) : 使用精讲(全)
C++11之后引入了std::tuple,俗称元组,元组(tuple)是一种用于组合多个不同类型的值的数据结构。元组可以将不同类型的数据打包在一起,类似于一个容器,可以按照索引顺序访问其中的元素。元组的大小在编译时确定,不支持动态添加或移除元素。std::tuple类似互C语言的结构体,不需要创建结构体而又有结构体的特征,在某些情况下可以取代结构体而使得程序更加简洁,直观。std::tuple理论上可以定义无数多个不同类型的成员变量。原创 2024-02-03 15:44:14 · 2939 阅读 · 20 评论 -
C++反射之检测struct或class是否实现指定函数
诸如Java, C#这些语言是设计的时候就有反射支持的。c++没有原生的反射支持。并且,c++提供给我们的运行时类型信息非常少,只是通过typeinfo提供了有限的一些支持。这一点点支持其实连类型名都无法打印好。更别说去检测一个结构体或类是否具有实现指定函数。通过编写模板代码和或requires(C++20)表达式,你可以根据某个类型是否拥有特定的成员函数或方法来启用或禁用某些代码。这种方法不会直接告诉你一个类型是否实现了某个函数,但它允许你根据类型的能力编写条件编译的代码。原创 2024-05-08 22:07:00 · 313 阅读 · 6 评论 -
C++实现自定义对象支持Range-based循环语法
自定义类支持range-base for需要满足的条件:1)类中需要定义容器相关的迭代器(这里的迭代器是广义的,指针也属于该范畴)2)类中要有begin()和end()的成员方法,返回值为迭代器(或重载全局的begin()和end()也可以)//返回第一个迭代子的位置//返回最后一个迭代子的下一个位置3)迭代器必须支持!=、*解引用、前置++等操作operator++(自增),可以在自增之后返回下一个迭代子的位置operator!= (判不等)operator* (解引用)原创 2024-05-08 11:33:04 · 746 阅读 · 5 评论 -
C++之内联(inline)
内联的优势其实可以分成两个部分,一个是调用方面的,比如前面说的出栈入栈等;另外一个是调用时的优化,比如函数代码如果成为内联函数,编译就可以把一些类似的固定计算直接指定为计算的结果值。而内联的劣势,主要就在于内联导致的代码膨胀,而有些时候过度内联反而会导致性能的丧失。明白了内联的优缺点,就可以根据自己的实际开发需求来进行使用了。整体上而言,内联函数适合于小型、高频函数的调用,通常可以在ORM的数据库属性读写中看到。原创 2024-05-05 18:57:03 · 840 阅读 · 2 评论 -
C/C++零长度数组的妙用
其实零长度数组是一个技巧,这样的小技巧在C/C++中有很多。它们在一些特定的场景下有着非常好的应用,不过前面的定语一定要记清楚,特定的场景。这也是C/C++让初学者感到难缠的一个重要原因。到处都有一些特殊情况,而特殊情况里可能又套着特殊情况。这种小技巧的东西,不用刻意学习,用到了,想起来有,查查资料用就可以了。原创 2024-05-05 11:44:00 · 566 阅读 · 2 评论 -
C++中的explicit关键字详解
在C++中,explicit关键字用于防止类构造函数、转换运算符或其他函数的隐式自动转换。使用explicit可以提高代码的可读性和健壮性,避免意外的类型转换导致的错误。以下是关于explicit关键字的详细介绍和示例。原创 2024-05-03 09:15:14 · 269 阅读 · 8 评论 -
C++临时对象的产生及优化
优化是一个迭代的过程,需要根据具体的代码和用例进行调整。在优化之前,最好先测量代码的性能,以便了解优化的效果。同时,也要注意不要过度优化,以免引入难以维护的代码或产生意外的副作用。原创 2024-05-01 07:23:16 · 771 阅读 · 6 评论 -
C++14之std::exchange的使用和原理分析
1) 原子性:std::exchange 提供了原子操作,这意味着在交换过程中,其他线程不会看到中间状态。这对于需要精确控制数据状态的多线程应用程序非常有用。2) 返回值:std::exchange 返回交换前的值。这允许你在一个操作中同时获取和设置值。3) 用途广泛:除了直接的数据交换,std::exchange 还可以与算法和其他模板一起使用,以提供更复杂的操作。4) 与 std::swap 的区别:std::swap 也是用于交换两个值的函数,但它不保证原子性。原创 2024-04-29 16:11:25 · 552 阅读 · 9 评论 -
手撕代码: C++实现数据的序列化和反序列化
在C++应用程序中,经常会涉及到对一些数据进行序列化和反序列化的处理。序列化可以将一个对象转换为一串字节流,这样就可以将其存储在硬盘上或者通过网络传输到其他设备上。而反序列化则是将这些字节流解析成原始的对象。在Qt中,数据的序列化和反序列化可以使用QDataStream类来完成。QDataStream是一个方便的Qt类,它可以将基本数据类型、Qt数据类型以及用户定义的数据类型都进行序列化和反序列化。在使用QDataStream进行序列化时,需要指定一个QIODevice类的子类(例如QF原创 2024-04-24 21:42:54 · 933 阅读 · 3 评论 -
C++中不使用中间变量交换两个变量值的方式
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。3) 在实际编程中,如果对变量的值范围有明确的了解,并且确信不会导致溢出,可以使用算术运算符进行交换。这种算法先将a和b的值赋给a,之后b等于a-b,这是b的值就变成了原来的a,最后a=a-b,a的值变为原来的b。如果a和b的值非常大,相加后可能会导致整数溢出,从而导致交换后的值不正确。交换两个数的值是比较基础也比较常用的算法,一般在交换两数的值是,最简单的方法适用的方法就是。^ : 异或运算,转成2进制,再相加。原创 2024-04-20 22:11:48 · 500 阅读 · 10 评论 -
C++进阶技巧:如何在同一对象中存储左值或右值
要定义const访问,需要使变量内部的三种可能类型中的每一种都产生一个const引用。为了访问变量中的数据,将使用std::visit和规范的overload要获得const引用,只需为每种variantoverload(},},),storage非const引用的创建使用相同的技术,除了variant是之外,它不能产生非const引用。然而,当std::visitoverload(},},*/ }),storageoverload(},},),storage。原创 2024-04-16 13:40:11 · 1369 阅读 · 3 评论 -
C 语言中的多态性:结构体与函数指针的巧妙结合
多态性是面向对象编程中的一个重要概念,它允许不同类型的对象对相同的消息做出不同的响应。在 C 语言中,我们虽然没有类和对象的概念,但我们仍然可以通过结构体和函数指针来模拟多态性的行为。具体来说,我们可以通过定义一个包含函数指针的结构体,并在派生(子类)结构体中包含基类(父类)结构体的方式来实现多态性。 我们知道结构体的内存布局是连续的,结构体的成员按照定义的顺序依次存放在内存中。这为多态性的实现提供了基础,因为我们可以在派生类中包含基类的结构体,从而保证派生类对象的内存布局与基类对象兼容。原创 2024-04-15 23:36:10 · 877 阅读 · 9 评论 -
C++可调用Callable类型的总结
可调用(Callable) 类型是可应用 INVOKE 操作(std::invoke 是在 C++17 里定义的类, 感觉意思就是执行函数操作的模板类.)原创 2024-04-12 21:29:09 · 1238 阅读 · 17 评论 -
C++继承多接口,调用虚函数跳转到错误接口的虚函数的奇怪问题
1) C++对象的内存模型(内存布局)2)数据转换static_cast的用法,延伸的还有const_cast、dynamic_cast、reinterpret_cast。原创 2024-04-11 23:05:15 · 996 阅读 · 6 评论 -
C++17中的结构化绑定详解
总体而言,结构化绑定是C++17中一个非常有用的特性,它可以让我们的代码更简洁、易读,提高开发效率。通过结构化绑定,我们可以轻松地从数组、元组、结构体、类等多种数据结构中提取元素,并为它们分别赋予变量名。此外,结构化绑定还可以与范围for循环结合使用,简化对容器元素的处理。原创 2024-04-10 22:30:48 · 537 阅读 · 5 评论 -
C/C++中重载函数取地址的方法
上述代码[1],[2],[3]处都会出现编译错误,那是因为函数重载,多个函数名相同,找不到该用那个函数地址。这个时候解决办法就是人为指定用那个函数,那么人为指定用那个函数有哪些办法呢?原创 2024-03-29 15:06:41 · 908 阅读 · 17 评论 -
C++之std::mem_fn使用和实现原理(全)
允许我们将成员函数、数据成员或指向成员的指针转换为可调用的对象。这使得我们可以更加灵活地处理成员函数,特别是在需要将其作为回调或策略参数传递时。通过,我们可以避免直接使用函数指针或成员指针,从而简化代码并提高可读性。返回的对象可以存储并传递给其他函数或对象,以便稍后使用。需要注意的是,生成的函数对象需要接收一个对象实例作为第一个参数(对于非静态成员函数),然后才能调用该成员函数。对于数据成员,它返回的是对该成员的引用或指针,取决于数据成员的类型。原创 2024-03-27 14:51:39 · 849 阅读 · 6 评论 -
C++手动实现定时器
skynet 是怎么样运转定时器的?skynet的 timer 线程会不断触发 expire_timer函数,在该函数中会不断执行timer_execute对 near 中的时器执行超时操作。执行完毕后,调用 timer_shift 从t[0] ~ t[3]中选择合适的定时器节点加入到 near 中,这过程就相当于提高了定时器节点的紧急程度(因为随着时间的流逝,定时器节点的紧急程度会越来越向near逼近)。转载 2024-03-24 13:45:04 · 531 阅读 · 7 评论 -
std::thread使用及实现原理精讲(全)
线程创建和销毁是昂贵的操作,应尽量避免频繁创建和销毁线程。线程间共享数据时,要确保数据访问的线程安全性。尽量避免在多个线程中访问和修改全局变量或静态变量,除非这些变量是线程安全的。使用 std::thread 时,要确保在程序结束前对所有线程调用 join() 或 detach(),以避免资源泄漏。总之,std::thread 为 C++ 提供了强大而灵活的多线程支持,使得开发者能够更容易地编写并行程序。然而,多线程编程也带来了额外的复杂性和挑战,需要开发者仔细考虑线程间的数据共享和同步问题。原创 2024-03-22 22:44:41 · 1493 阅读 · 3 评论 -
有了std::thread,为什么还需要引入std::jthread?
C++11以来提供了C++原生的多线程std::thread,这极大的方便了多线程的书写。在此之前书写多线程时需要平台原生API,这对于跨平台尤其是跨多平台程序来讲,多线程部分代码书写及维护都是极大的工作量。}};运行如上代码时,会出现崩溃,堆栈信息如下:由如上堆栈信息可知,崩溃原因为std::thread在析构时,如果对象仍为joinable状态,则会触发中断,为避免崩溃需要在std::thread析构器前需要将其置于非joinable状态,即需要主动调用join或detach接口。原创 2024-03-20 15:58:04 · 1093 阅读 · 15 评论 -
C++14之std::index_sequence和std::make_index_sequence
std::index_sequence和std::make_index_sequence结合使用这种方法是模板元编程中的一个常见技巧,它允许我们在编译时生成和执行复杂的操作,而不需要在运行时付出任何额外的性能开销。原创 2024-03-12 08:17:18 · 901 阅读 · 10 评论 -
C++无锁队列的原理与实现
生产环境中广泛使用生产者和消费者模型,要求生产者在生产的同时,消费者可以进行消费,通常使用互斥锁保证数据同步。但线程互斥锁的开销仍然比较大,因此在要求高性能、低延时场景中,推荐使用无锁队列。kfifo是Linux内核的一个FIFO数据结构,采用环形循环队列的数据结构来实现,提供一个无边界的字节流服务,并且使用并行无锁编程技术,即单生产者单消费者场景下两个线程可以并发操作,不需要任何加锁行为就可以保证kfifo线程安全。原创 2024-01-20 08:00:00 · 1354 阅读 · 5 评论 -
C++内存泄漏检测
使用宏定义,替换系统的内存分配接口。并利用__FILE__、__LINE__分别获取当前编译文件的文件名、行号,进行追踪位置信息。需要注意的是,宏定义一定要放在内存分配之前,这样预编译阶段才会替换为我们自己实现的_malloc和_free。原创 2024-03-07 07:42:39 · 1067 阅读 · 3 评论 -
C++17之std::invoke: 使用和原理探究(全)
std::invoke是 C++17标准库中引入的一个函数模板,它的引入就是为了解决这个问题,它提供了一种统一的调用语法,无论是调用普通函数、函数指针、类成员函数指针、仿函数、std::function、类成员还是lambda表达式,都可以使用相同的方式进行调用。原创 2024-03-01 16:54:28 · 2287 阅读 · 26 评论 -
C++之std::tuple(二) : 揭秘底层实现原理
std::tuple存储的递归写法基于这样的思想:一个包含N(N>0)个元素的元组可以存储为一个元素(第1个元素,或者说是列表的头部)加上一个包含N-1个元素的元组(尾部),而包含0个元素的元组是单独的特殊情况。原创 2024-02-25 16:48:42 · 1936 阅读 · 13 评论 -
C++三剑客之std::any(一) : 使用详解
C++17的分别是。今天主要讲std::any。std::any类用于任何可拷贝构造类型的单个值的类型安全容器。在头文件中,c++标准库定义了类std::any。从上面的定义可以看出std::any不是模版类,而是一种很特殊的容器,它只能容纳一个元素,但这个元素可以是任意的类型,可以是基本数据类型(int,double,char,float...)也可以是复合数据类型(类、结构体)。std: any是一种值类型,它能够更改其类型,同时仍然具有类型安全性。原创 2024-02-07 22:54:35 · 2732 阅读 · 8 评论 -
C++三剑客之std::optional(一) : 使用详解
类模板std::optional管理一个可选 的容纳值,既可以存在也可以不存在的值。 一种常见的optional使用情况是一个可能失败的函数的返回值。与其他手段,如std::pair相比,optional良好地处理构造开销高昂的对象,并更加可读,因为它显式表达意图。原创 2024-02-12 21:11:42 · 2747 阅读 · 8 评论 -
C++之RTTI实现原理
C++的RTTI为程序员提供了在运行时获取类型信息的便利,但在某些情况下,特别是涉及性能要求高的应用中,开发者可能需要权衡使用默认RTTI机制的开销,并考虑是否需要自定义实现以满足特定需求。自定义实现RTTI可以提供更灵活和高效的类型信息管理方式。我们设计RTTI时,基本上是通过宏的方式载入一些虚函数或者类型来处理一个class,在运行时识别到具体类型,就可以通过static_cast来进行安全转换。原创 2024-02-05 21:49:04 · 1292 阅读 · 19 评论 -
为什么C++17要引入std::string_view?
std::string_view的优点:1)高效性:std:string_view主要用于提供字符串的视图(view),使std::string_view拷贝字符串的过程非常高效,永远不会创建字符串的任何副本,不像std::string会效率低下且导致内存开销。std::string_view不拥有字符串数据,它仅提供对现有字符串的视图或引用(view or reference)。这使得它适合需要访问或处理字符串而无需内存分配或重新分配开销的场景,特别是在处理大量字符串时非常有用。原创 2024-01-21 16:46:02 · 2527 阅读 · 13 评论 -
C++三剑客之std::variant(二):深入剖析
本文我们主要研究问题模板类std::variant如何做到存任意多个类型值的容器?不同类型怎么做到巧妙的构造与转换的?多种构造函数如何实现?内部数据怎么储存?为什么不能保存引用、数组和void类型?std::variant是在头文件variant中,是C++17引入的,本文以VS2019平台展开讲解variant的原理和深层次用法。std::negation 逻辑非元函数,一元函数对象类,其调用将返回对其实参求反的结果(由一元操作符-返回)。"");"");int main()原创 2024-01-17 17:58:42 · 2300 阅读 · 3 评论 -
C++之std::is_object
std::is_object是一个用于元编程的C++类型特性,用于判断一个类型是否是对象类型。只需在代码中调用std::is_object模板,并传入要检查的类型名,即可判断该类型是否为对象类型。在编写代码时,需要注意std::is_object判断的是类型是否为对象类型,而不是类类型或枚举类型。同时,在使用std::is_object模板进行类型检查时,需要注意传入的类型名中不要包含已删除的引用和cv限定符。原创 2024-01-16 13:56:13 · 1453 阅读 · 8 评论 -
C++之std::decay
std::decay是我们平时模版编程中使用的比较多的,在实际模板编程或者模板元编程中非常有用,在type_traits源代码里处处可见,实际工作中也会经常用到;上面的介绍只是抛砖引玉,要想真正掌握它,只有的不停地使用,在使用过程中遇到问题,解决问题,才能真正理解它的原理,灵活使用。原创 2023-12-29 10:35:51 · 1679 阅读 · 1 评论 -
C++三剑客之std::variant(一) : 使用
可以对 t 赋初值,对于基本类型,它是0、false还是nullptr。//输出: 3// ERROR以上都是我日常工作中对std::variant的用法的总结;做技术,要知其然,更要知其所以然,后面我将从std::varant的源码实现上继续分析它的原理,敬请期待。。。原创 2023-12-28 07:59:04 · 2682 阅读 · 6 评论 -
C++模板函数重载规则细说
文章真的长呀,如果你能坚持看到这里,说明你是一个非常坚持且对编程有强烈兴趣的人,希望这篇文章让你在c++模板的路上有所帮助。那么接下来我们再来回顾一下这篇文章的内容。我们先介绍了模板元编程要解决的场景与问题然后我们从一个具体的模板元编程例子展开,一步步学习了模板元编程的整体内容接下来针对其核心:模板函数重载匹配规则以及模板规则进一步了解最后再给出在使用方面的一些经验供参考模板元编程他要解决的最核心的问题就是:对模板类型的判断与选择。原创 2023-12-25 22:13:20 · 1495 阅读 · 5 评论 -
C++之std::declval
std::declval是C++11引入的一个模板函数,将任意类型T转换成右值引用&&类型,在 decltype 表达式中不必经过构造函数就能使用成员函数;通常在模板中使用 std::declval时,模板接受的模板实参通常可能无构造函数,但有同一成员函数,均返回所需类型。原创 2023-12-19 20:04:06 · 1072 阅读 · 1 评论