C/C++智能指针

article/2025/9/19 12:19:12

目录

1.1RAII(资源获取几初始化)

 1.2auto_ptr

1.3unique_ptr

1.4shared_ptr

1.5weak_ptr


 我们在在动态开辟空间的时候,malloc出来的空间如果没有进行释放,那么回传在内存泄漏问题。或者在malloc与free之间如果存在抛异常,那么还是有内存泄漏安全。因此我们在这里引入了智能指针来对资源进行管理。(内存泄漏)

1.1RAII(资源获取及初始化)

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法的好处:

  • 不需要显示的释放资源。
  • 采用这种方式,对象所需要的资源在其生命期内始终保持有效。

总结:RAII就是一种管理资源自动释放的一种机制,初步看来,他通过类将资源包装起来。在进行资源初始化时,巧妙地利用编译器会自动调用构造函数预计析构函数的特性,来完成对资源的自动释放。在构造方法中,将资源放入,让对象进行释放,在析构方法中,将资源释放掉。

#include<iostream>
using namespace std;
//智能指针的原理:RAII+具有指针类似的行为
//我们在这里自己进行封装
template<class T>
class Smartptr{
public:Smartptr(T* p = nullptr) :ptr(p){}~Smartptr(){if (ptr){//此时指针如果不为空且具有释放的权利的时候,则将其释放,且将owner重新职位falsedelete ptr;ptr = nullptr;}}//在使用指针是我们有*与->的使用,因此在这里要对齐进行运行算符重载//重载*T& operator*(){return *ptr;}//他只能在指针指向的是对象或者是结构体的时候来使用T& operator->(){return ptr;}//某些情况下使用原生态指针T* get(){return ptr;}
private:T* ptr;//采用类进行指针管理
};
int main(){Smartptr<int> st1(new int);Smartptr<int> at2(st1);//此时调用拷贝构造函数,但是这个类里面没有,因此只能使用默认的拷贝构造//因此是浅拷贝return 0;
}

根据上面代码,我们先简单的模拟了一下智能指针发现了存在这一个致命的问题,如果当一个对象对另一个对象进行拷贝构造时,由于没有定义拷贝构造函数,那么就会使用到默认的拷贝构造函数,产生浅拷贝问题。又因为所有的智能指针都是一样的,那如何解决浅拷贝问题呢?我们在前面学习string类时,对浅拷贝的解决方式时使用深拷贝,但是在这里我们不能使用深拷贝,在string类中,因为其内部要存字符串,需要申请空间,而string类中的空间是自己申请与维护的,而智能指针的资源是用户提供的,如下图:

 智能指针不能申请资源只能提用户来管理资源,因此此处不能使用深拷贝的方式来解决问题。

 1.2auto_ptr

 资源完全转移

我们参考C++98版本的库中就提供了auto_ptr的智能指针是如何解决浅拷贝问题的。

namespace bite{template<class T>class auto_ptr{public:// RAII : 保证资源可以自动释放auto_ptr(T* ptr = nullptr): _ptr(ptr){}~auto_ptr(){if (_ptr){delete _ptr;_ptr = nullptr;}}// 解决浅拷贝方式:资源转移// auto_ptr<int>  ap2(ap1)auto_ptr(auto_ptr<T>& ap): _ptr(ap._ptr){ap._ptr = nullptr;}// ap1 = ap2;auto_ptr<T>& operator=(auto_ptr<T>& ap){if (this != &ap){// 此处需要将ap中的资源转移给this// 但是不能直接转移,因为this可能已经管理资源了,否则就会造成资源泄漏if (_ptr){delete _ptr;}// ap就可以将其资源转移给this_ptr = ap._ptr;ap._ptr = nullptr;   // 让ap与之前管理的资源断开联系,因为ap中的资源已经转移给this了}return *this;}// 对象具有指针类似的行为T& operator*(){return *_ptr;}T* operator->(){return _ptr;}T* Get(){return _ptr;}private:T* _ptr;};
}
int main(){auto_ptr<int> st1(new int);auto_ptr<int> at2(st1);return 0;
}

我们观察上述代码,虽然他解决了浅拷贝问题,但是他又引入了新的问题,。当对象拷贝或者赋值后,前面的对象就悬空了。它的缺陷就是当我们想访问或者修改st1对象的时候,代码会崩溃。

资源管理权限转移

 为了解决上面的问题有使用了转移资源管理权限的思想。

#include<iostream>
using namespace std;
//智能指针的原理:RAII+具有指针类似的行为
//我们在这里自己进行封装
template<class T>
class autoptr{
public:autoptr(T* p = nullptr) :ptr(p), owner(true){}~autoptr(){if (ptr && owner){//此时指针如果不为空且具有释放的权利的时候,则将其释放,且将owner重新职位falsedelete ptr;owner = false;}}//在使用指针是我们有*与->的使用,因此在这里要对齐进行运行算符重载//重载*T& operator*(){return *ptr;}//他只能在指针指向的是对象或者是结构体的时候来使用T& operator->(){return ptr;}//某些情况下使用原生态指针T* get(){return ptr;}//因此在这里解决浅拷贝问题//资源管理权限的转移autoptr(autoptr<T>& p) :ptr(p.ptr), owner(p.owner){p.owner = false;}T& operator=(autoptr<T>& p){//赋值运算符的重载if (this == p){//首先判断是否是自己给自己复制return p;}if (ptr && owner){//如果此时ptr不为空且具有权限,那么此时就将现在的资源释放掉,顺便拿到p的权限delete ptr;ptr = p.ptr;owner = p.owner;p.owner = false;}}//某些情况下使用原生态指针
private:T* ptr;//采用类进行指针管理
};
int main(){autoptr<int> st1(new int);autoptr<int> at2(st1);//此时调用拷贝构造函数,但是这个类里面没有,因此只能使用默认的拷贝构造函数//因此是浅拷贝return 0;
}

 如上面代码,当发生拷贝构造或者赋值时,将被拷贝对象中资源转移给新对象,然后让被拷贝对象与资源断开联系,这样就解决了一块空间被多个对象使用而造成程序崩溃问题。但是在这里存在着致命缺陷。再对st1进行拷贝后将其的指针赋值为空,导致了st1对象悬空,通过st1对象访问资源就会出现问题,会造成野指针,使代码崩溃。因此要在这里说明什么情况下对不要使用auto_ptr。

1.3unique_ptr

 上面的问题都是因为发生了拷贝构造然后造成的,因此unique_ptr在这里采用的方式是禁止拷贝。也就是说,一份资源只能被一个对象来进行管理,对象之见不能共享资源(资源独占)。解决浅拷贝方式--资源独占,防止拷贝,在这里有两种方案,第一种:C++98中的方案,将拷贝构造函数以及赋值运算符重载方法只进行声明不进行定义,并且将其权限给成私有的,这样就防止其被拷贝。第二种:C++11种的方案:可以让编译器不生成默认的拷贝构造以及赋值运算符delete,delete关键字它的扩展功能就是从堆上进行释放资源,用其修饰默认的构造函数,表明编译器不会生成了。


#include<iostream>
using namespace std;
//智能指针的原理:RAII+具有指针类似的行为
//我们在这里自己进行封装
template<calss T>
class DF_new{
public:void operatr()(T*& ptr){if(ptr){delete ptr;ptr = nullptr;}}
};
template<calss T>
class DF_free{
public:void operatr()(T*& ptr){if(ptr){free(ptr);ptr = nullptr;}}
};
//关闭文件指针
template<calss T>
class DF_close{
public:void operatr()(FILE*& ptr){if(ptr){fclose(ptr);ptr = nullptr;}}
};
//T:资源中所放的数据的类型
//DF:资源的释放方式
template<class T,class DF = DF_new<T>>//DF释放的方式
class uniqueptr{
public:uniqueptr(T* p = nullptr) :ptr(p){}~uniqueptr(){if (ptr){//对于ptr管理的资源,有可能是从堆上申请的内存空间,文件指针,malloc空间...//因此他在释放的是否是要进行考虑的,是不同的,解决的方式就是对这个类再加上一个模板参数列表即可ptr = nullptr;}}//在使用指针是我们有*与->的使用,因此在这里要对齐进行运行算符重载//重载*T& operator*(){return *ptr;}//他只能在指针指向的是对象或者是结构体的时候来使用T& operator->(){return ptr;}//某些情况下使用原生态指针T* get(){return ptr;}//解决浅拷贝方式--资源独占,防止拷贝,在这里有两种方案//第一种:C++98中的方案:
private:uniqueptr(const uniqueptr<T,DF>&);uniqueptr<T&>operator=(const uniqueptr<T,DF>&);//第二种:C++11中的方案:可以让编译器不生成默认的拷贝构造以及赋值运算符--deleteuniqueptr(const uniqueptr<T,DF>&) = delete;//表明编译器不会生成默认的赋值运算符重载uniqueptr<T,DF>& operator=(const uniqueptr<T,DF>&) = delete;
private:T* ptr;//采用类进行指针管理
};

在这里说明一下为什么在C++98中对其拷贝构造函数与赋值运算符重载只进行定义,不声明不定义,且将其权限给成私有的。如果没有将其设置为私有的,那么用户就会在外部对其方法进行定义。

unique_ptr指针适用于资源被一个对象管理并且不会被共享。他的缺陷就是多个对象中资源无法进行共享,因此使用到了shared_ptr指针。

1.4shared_ptr

共享指针,对个对象之间可以共享资源。在这里采用引用计数的方式来进行浅拷贝的。引用计数实际上就是一个整形空间,记录使用资源的对象的个数,在释放之前,让最后一个使用资源的的对象来进行释放。

#include<iostream>
using namespace std;
//智能指针的原理:RAII+具有指针类似的行为
//我们在这里自己进行封装
template<class T,class DF = DF_new<T>>
class sharedptr{
public:sharedptr(T* p = nullptr) :ptr(p),p_count(nullptr){if(ptr){//此时只有当前建好的一个对象在使用该份资源p_count = new int(1);}}~sharedptr(){if (ptr && 0 == --(*count)){DF df;df(ptr);delete p_count;p_count = nullptr;}}//在使用指针是我们有*与->的使用,因此在这里要对齐进行运行算符重载//重载*T& operator*(){return *ptr;}//他只能在指针指向的是对象或者是结构体的时候来使用T& operator->(){return ptr;}//某些情况下使用原生态指针T* get(){return ptr;}//用户可能需要获取引用计数int use_count()const{return *p_count;}//解决浅拷贝方式,引用计数sharedptr(const sharedptr<T,DF>& sp):ptr(sp.ptr),p_count(sp.p_count){if(ptr){++(*p_count);}}sharedptr<T,DF>& operator=(const sharedptr<T,DF>& sp){if(this != &sp){//在sp共享之前,需要将之前的资源进行释放if(ptr && 0 == --*(p_count)){//如果此时之前的内容只有他一个进行管理,那么直接进行释放DF df;df(ptr);delete p_count;}//this就可以与sp进行共享了ptr = sp->ptr;p_count = sp->p_count;if(p_count){p_count++;}}return *this;}private:T* ptr;//采用类进行指针管理int* p_count;//指向的是使用资源的对象的个数
};

释放的操作:先检测是否有资源,有资源即是pcount>=1,先给计数器进行-1操作,然后检测计数器是否为0,如果是0,则说明当前对象是最后使用资源的对象,,需要将资源以及计数空间进行释放,当为非0的时候,说明还有其他对象在使用资源,当前资源不需要释放。

我们观察上面的代码,可以判断吹他在单线程下是没有出现问题的,但是在多线程下可能是有问题的。多线程下有多个执行流,CPU也是多核的,多个线程同时往下执行,假设现在连个线程中的智能指针共享的是同一份资源,两个线程结束时,需要将其管理的资源释放掉。也有情况下,线程同事进行判断,使得最后导致资源没有进行释放,而引起资源泄漏。因此,在遇到共享的资源,变量等等之类的,需要考虑多线程环境下的安全性。因此最常见的方式是对其进行加锁。在这里进行加锁,是为了保证自身的安全性。


#include<iostream>
using namespace std;
//智能指针的原理:RAII+具有指针类似的行为
//我们在这里自己进行封装
template<class T,class DF = DF_new<T>>
class sharedptr{
public:sharedptr(T* p = nullptr) :ptr(p),p_count(nullptr),mutex(new mutex){if(_ptr){p_count = new int(1);}}~sharedptr(){reldef();}//在使用指针是我们有*与->的使用,因此在这里要对齐进行运行算符重载//重载*T& operator*(){return *ptr;}//他只能在指针指向的是对象或者是结构体的时候来使用T& operator->(){return ptr;}//某些情况下使用原生态指针T* get(){return ptr;}//用户可能需要获取引用计数int use_count()const{return *p_count;}//解决浅拷贝方式,引用计数sharedptr(const sharedptr<T,DF>& sp):ptr(sp.ptr),p_count(sp.p_count),_pmutex(sp._pmutex){Addref();}sharedptr<T,DF>& operator=(const sharedptr<T,DF>& sp){if(this != &sp){//在sp共享之前,需要将之前的资源进行释放reldef();//this就可以与sp进行共享了ptr = sp->ptr;p_count = sp->p_count;_pmutex = sp._pmutex;Addref();}return *this;}
private:void Addref(){//对加法进行处理if(!ptr) return;_pmutex->lock();++(*p_count);_pmutex->unlock();}//此时我们还需要判断锁是否需要释放void reldef(){//对减法进行处理if(ptr) return;		bool isdelete = false;_pmutex->lock();if (ptr && 0 == --(*count)){DF df;df(ptr);delete p_count;p_count = nullptr;//当资源释放完毕后,对其进行标记isdelete = true;}_pmutex->unlock();if(isdelete){delete(_pmutex);}}
private:T* ptr;//采用类进行指针管理int* p_count;//指向的是使用资源的对象的个数mutex* _pmutex;//加上锁的原因是要保证在这里引用计数的操作是原子性的
};

虽然shared_ptr在这里是可以避免拷贝构造带来的错误,但是他自身也有缺陷。在使用shared_ptr时可能会引起循环引用。什么是循环引用呢?我们先举个例子。

#incldue<memory>
struct ListNode{shared_ptr<ListNode*> next;shared_ptr<ListNode*> prve;int data;shared(int x):next(nullptr),prev(nullptr),data(x){cout<<"ListNode(int)"<<this<<endl;}~ListNode(){cout<<"~ListNode():"<<this<<endl;}
};
void Looptest(){//将两个节点分别交给智能指针来管理shared_ptr<ListNode> sp1(new ListNode(10));shared_ptr<ListNode> sp2(new ListNode(20));cout<<sp1.use_count()<<endl;cout<<sp2.use_count()<<endl;sp1->next = sp2;sp2->prev = sp1;cout<<sp1.use_count()<<endl;cout<<sp2.use_count()<<endl;
}
int main(){Looptest();
}

当shared_ptr管理的资源在相互指向的时候,我们看上面代码的运行情况:在结果中,我们发现运行时并未出现调用析构函数的结果,在这里没有释放掉资源,因此会引起资源泄露问题。也就是说,循环引用是指两个对象之间形成了环路,在智能指针shared_ptr中存在这个问题,他的引用计数不为0。也就是两份资源分别等待对方先进行释放,最后导致了内存泄漏。处理这种现象十分简单,只需要只使用一个weak_ptr即可。

1.5weak_ptr

weak_ptr的实现原理是使用了引用计数进行实现的,他不可以进行资源的管理,唯一的作用就是配合shared_ptr解决循环引用的问题。


#incldue<memory>
struct ListNode{weak_ptr<ListNode*> next;weak_ptr<ListNode*> prve;int data;shared(int x):next(nullptr),prev(nullptr),data(x){cout<<"ListNode(int)"<<this<<endl;}~ListNode(){cout<<"~ListNode():"<<this<<endl;}
};
void Looptest(){//将两个节点分别交给智能指针来管理shared_ptr<ListNode> sp1(new ListNode(10));shared_ptr<ListNode> sp2(new ListNode(20));cout<<sp1.use_count()<<endl;cout<<sp2.use_count()<<endl;sp1->next = sp2;sp2->prev = sp1;cout<<sp1.use_count()<<endl;cout<<sp2.use_count()<<endl;
}
int main(){Looptest();
}



我们看上面的代码,此时析构函数执行了,并没有发生引用循环。

question:为什么weak_ptr可以解决循环引用?

原因是在他的引用计数上。如上图代码,我们进行分析:

 在标准库中,weak_ptr的引用计数维护了两份,由图可知,当开始执行时,use=weak=1;此时在执行sp1->next=sp2,因为sp1->next的类型是一个weak_ptr,因此此时的sp2的引用计数的weak++,再执行sp2->prve=sp1,因为sp2->prve的类型也是一个weak_ptr,因此此时的sp1的引用计数weak++;此时sp1指向空间中的计数use=1,weak=2,sp2指向的资源空间的计数也是一样。

现在要对资源进行释放。首先释放sp2,因为sp2的类型是一个shared_ptr,use--等于0,说明此时资源是可以进行释放的,因此就要对对象内部的每一个资源进行释放掉,sp2->prev是weak_ptr类型,将其销毁,那么左面资源的中的引用计数weak--,然后sp2->prve与sp1断开,next指针也销毁掉了,因此此时的节点也销毁掉了,所以sp2的pcount与资源的引用计数断开,右面的资源的引用计数weak--。

现在进行释放sp1,因为sp1的类型是一个shared_ptr,use--等于0,说明此时资源是可以进行释放的,因此就要对对象内部的每一个资源进行释放掉,sp1->next是weak_ptr类型,将其销毁,那么右面资源的中的引用计数weak--,此时右面的引用计数的weak=0,因此就可以将右面资源的引用计数进行释放;左面资源的prve指针此时也销毁了,此时节点进行销毁,所以sp1的pcount与资源的引用计数断开,左面的weak--等于0,此时将左面的资源的引用计数进行销毁。

总结:当一个资源被shared_ptr共享时,use++;当一个资源被weak_ptr共享时,weak++。且只有shared_ptr可以独立的管理资源。

question:unique_ptr与shared_ptr能否可以管理一块连续空间?

可以。如果要管理里一段连续的空间,我们必须自己实现删除器,operator()(T*&ptr){delete[] ptr;ptr=nullptr;}。但是没有什么意义,对于连续空间,一般是不会直接交给智能指针进行管理的,因为在STL中已经有了vector。


http://chatgpt.dhexx.cn/article/OWZLWU7X.shtml

相关文章

Qt 之 智能指针汇总

来源 还有其他一些&#xff0c;做了一些汇总和测试&#xff0c;就不全列了。 文章目录&#xff1a; 一、垂悬指针的问题 二、Qt中的智能指针 1、QPointer 2、QSharedPointer & QWeakPointer 3、QScopedPointer 4、其他智能指针 三、实践记录 …

智能指针用法及其使用代码详解

网络上大多有关智能指针的解析只停留于简单的字面理解&#xff0c;今天来详细解析一下三种智能指针的用法以及具体的代码。 目录 概念 RAII机制介绍 智能指针雏形 shared_ptr原理介绍 shared_ptr使用方法 unique_ptr weak_ptr 概念 智能指针不是一个指针&#xff0c;它…

C++ 智能指针

shared_ptr 智能指针也是模板类&#xff0c;因此当我们创建一个智能指针是要提供额外的信息——指针可以指向的类型。默认初始化的智能指针保存着一个空指针。shared_ptr允许多个指针指向同一对象。 shared_ptr<string> p1; //可指向string shared_ptr<list<int&…

【C++】智能指针详解

今天我们来讲一下c中的智能指针。 目录 1. 智能指针初识1.1 什么是智能指针1.2 智能指针发展历史1.3 为什么需要智能指针 3. 智能指针原理3.1 RALL3.2 智能指针的分类3.2.1 auto_ptr3.2.2 unique_ptr3.2.3 shared_ptr3.2.3.1 shared_ptr 原理3.2.3.2 shared_ptr 的模拟实现3.2.…

智能指针详解

目录 前言 1、为什么需要智能指针&#xff1f; 2、智能指针的原理 3、智能指针的分类 3.1 auto_ptr 3.2 unique_ptr 3.3 shared_ptr 前言 C11中引入了智能指针的特性&#xff0c;本文将详细介绍智能指针的使用。 1、为什么需要智能指针&#xff1f; 我们来看一段代码&…

【c++复习笔记】——智能指针详细解析(智能指针的使用,原理分析)

&#x1f482; 个人主页:努力学习的少年&#x1f91f; 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 目录 一. 智能指针的基本概念 二. 智能指针的定义和使用 三. a…

C++ 智能指针 - 全部用法详解

为什么要学习智能指针&#xff1f; 咳咳&#xff0c;这个问题不是问大家的&#xff0c;是询问我自己的&#xff01; 我依稀记得刚离校出来找实习工作那会儿(2020年7月)&#xff0c;去面试一份工作&#xff0c;面试官问了我许多问题&#xff0c;其中有一个问题就是问&#xff1a…

AndroidStudio编译时 CXX1405 错误解决

AndroidStudio 编译带C的native库项目时报错&#xff0c; [CXX1405] error when building with cmake using D:\WorkSpace\AndroidXXXX\app\src\main\cpp\CMakeLists.txt: Build command failed.解决方法&#xff1a; cmd 到 Android SDK的cmake路径下&#xff0c;执行 cmake …

硬件速攻-AT24CXX存储器

AT24C02是什么&#xff1f; AT24CXX是存储芯片&#xff0c;驱动方式为IIC协议 实物图&#xff1f; 引脚介绍&#xff1f; A0 地址设置角 可连接高电平或低电平 A1 地址设置角 可连接高电平或低电平 A2 地址设置角 可连接高电平或低电平 1010是设备前四位固定地址 &#xf…

【dbus-cxx】libsigc++ 和 dbus-cxx 在 Ubuntu 中的编译和配置

文章目录 参考资料配置环境cmakelibsigcdbus-cxx 例程server.cppclient.cppMakefile运行结果 此帖作为自己学习记录使用&#xff0c;尚未使用交叉编译&#xff0c;仅在本地使用 参考资料 需先了解DBUS基础知识&#xff0c;建议看DBUS官方文档 DBUS-CXX也是建议看官方文档&…

正点原子IIC例程讲解笔记(三)——24cxx.c中函数理解

目录 一、24C02 简介 二、在 AT24CXX 指定地址写入一个数据&#xff1a; 三、在ATC24XX指定地址读出一个数据 四、检查AT24CXX是否正常&#xff1a;u8 AT24CXX_Check(void) 五、在 AT24CXX 里面的指定地址开始写入长度为 Len 的数据 六、在 AT24CXX 里面的指定地址开始读出…

windows用VS2019下编译log4cxx日志库

一、下载相关库文件 获取log4cxx源码包&#xff1a;http://logging.apache.org/log4cxx/index.html 获取依赖库apr和apr-util源码包:http://archive.apache.org/dist/apr/apr-1.2.11-win32-src.zip http://archive.apache.org/dist/apr/apr-util-1.2.10-win32-src.zip 编译apr…

log4cxx编译

本人进行过win7 64位操作系统和win10家庭版的log4cxx编译&#xff0c;使用的是vs2015&#xff0c;下面是详情。 1.sed下载 sed-4.2.1-bin.zip、sed-4.2.1-dep.zip下载地址&#xff1a;http://gnuwin32.sourceforge.net/packages/sed.htm 下载后&#xff0c;将sed的两个压缩包解…

【RT-Thread Master】at24cxx软件包使用笔记

硬件介绍 RT-Thread版本&#xff1a;V4.1.0软件包名称&#xff1a;at24cxxMCU型号&#xff1a;AT32F407VET7EEPROM型号&#xff1a;AT24C16 使用说明 1、使用menuconfig将软件包添加进入工程&#xff0c;路径如下所示。 2、把IIC总线打开&#xff0c;这里使用软件IIC&#…

linux下编译和安装log4cxx,ubuntu下log4cxx安装使用

需要安装log4cxx&#xff0c;安装的过程中可是充满了坎坷。。。最大的问题是在make log4cxx时&#xff0c;总是报undefined XML什么什么的错误&#xff0c;查了一下也没解决了&#xff0c;然后把apr-utils删了重新装了一下就好了。。 log4cxx现在是apache的一个项目&#xff0c…

linux下编译和安装log4cxx,RedHat如何安装log4cxx日志库

log4cxx日志库是一种动态库&#xff0c;用于记录c的日志&#xff0c;那么RedHat系统下要如何安装log4cxx日志库呢&#xff1f;下面小编就给大家介绍下RedHat安装log4cxx日志库的步骤&#xff0c;感兴趣的朋友不妨来了解下吧。 首先&#xff0c;我得到信息&#xff0c;安装这个库…

AT24Cxx读写全面理解

AT24Cxx - 电可擦可写E2PROM 芯片介绍 基础介绍\引脚介绍 AT24Cxx系列EEPROM是由美国Mcrochip公司出品&#xff0c;1-512K位的支持I2C总线数据传送协议的串行CMOS E2PROM&#xff0c;可用电擦除&#xff0c;可编程自定时写周期&#xff08;包括自动擦除时间不超过10ms&#…

mongodb-cxx-driver使用

mongocxx driver 是构建在 MongoDB C driver 之上的 1.首先需要安装mongo-c-driver wget https://github.com/mongodb/mongo-c-driver/releases/download/ 1.23.1/mongo-c-driver-1.23.1.tar.gz tar xzf mongo-c-driver-1.23.1.tar.gz cd mongo-c-driver-1.23.1 mkdir cmak…

老胡的周刊(第095期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 tabby[2] 自托管的 AI 编码助手&#xff0c;…

程序员养生指北

吴小胖第八次推送 阅读时间预计3分钟~ 熬夜篇 互联网人熬夜是不能避免的&#xff0c;原因却各不相同。 不加班的时候&#xff0c;总会对自己说&#xff0c;今天一定早睡&#xff0c;然鹅... 午休篇 熬夜的程序员总想依靠午休补觉&#xff0c;然鹅... 更不幸的是&#xff0c;互联…