浅谈auto_ptr智能指针

引入智能指针:
智能指针的实现原理:
资源分配即初始化RAII(Resource Acquisition Is Initialization):

定义一个类来封装资源的分配和释放,在构造函数完成资源的分配
和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

实现机制:利用类的构造和析构函数(释放资源)是由编译器自动调用的。
智能指针:
1.管理指针执行对象的释放问题。

2.可以像指针一样使用。

在c++标准库里主要有四个智能指针:

C++四种智能指针auto_ptr、unique_ptr、shared_ptr和weak_ptr。

其中auto_ptr是C++98标准化引入的;
scope_ptr、shared_ptr和weak_ptr是C++11标准化才引入的(当然,早在C++03的TR1中就已经可以使用了)。我们都知道,auto_ptr虽说简单,但使用起来却到处是坑,以至于大家都不提倡使用。
shared_ptr是引用计数的智能指针,被奉为裸指针的完美替身,因此被广泛使用。也可能正是这个原因,scope_ptr 和 weak_ptr似乎被大家遗忘了(或许还会以为它们纯属多余)。

上述言论引自网上
下面简单总结下这几个智能指针:

1.auto_ptr管理权转移
带有缺陷的设计 ----->c++98/03
在任何情况下都不要使用;

2.scoped_ptr(boost)
unique_ptr(c++11)
防拷贝--->简单粗暴设计--->功能不全。

3、shared_ptr(boost/c++11)
引用计数--->功能强大(支持拷贝、支持定制删除器)
缺陷---->循环引用(weak_ptr配合解决)。

这篇文章主要的内容是讲解auto_ptr所引出的一系列问题:


一、auto_ptr智能指针

无论在什么情况下都不要使用,下面来详细介绍下为什么不要使用它,可能会有人问,既然不让使用,那么为什么还要把它放在c++的标准库里呢?
是的,一开始我也是有这个疑问的,--->其实是因为c++标准库里的内容一经规定,就不允许修改了)

下面模拟实现其基本功能:

1.AutoPtr的第一种实现方法:

采用资源转移的方法。
一个指针将一块空间的权限完全交给了另一个指针。(权限的转移)



模拟实现代码如下:

[cpp] view plain copy
  1. <span style="font-size:18px;">template<class T>  
  2. class AutoPtr  
  3. {  
  4. public:  
  5.     AutoPtr(T* ptr = 0)//构造函数  
  6.         :_ptr(ptr)  
  7.     {  
  8.         ptr = NULL;  
  9.     }  
  10.   
  11.     AutoPtr(AutoPtr<T>& ap)//拷贝构造函数  
  12.         :_ptr(ap._ptr)  
  13.     {  
  14.         ap._ptr = NULL;  
  15.     }  
  16.   
  17.     AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值运算符重载  
  18.     {  
  19.         if (this != &ap)  
  20.         {  
  21.             if (_ptr)  
  22.             {  
  23.                 delete _ptr;  
  24.             }  
  25.             _ptr = ap._ptr;  
  26.             ap._ptr = NULL;  
  27.         }  
  28.         return *this;  
  29.     }  
  30.   
  31.     ~AutoPtr()//析构函数  
  32.     {  
  33.         if (_ptr)  
  34.         {  
  35.             delete _ptr;  
  36.             _ptr = NULL;  
  37.         }  
  38.     }  
  39.   
  40.     T& operator*()  
  41.     {  
  42.         return *_ptr;  
  43.     }  
  44.   
  45.     T* operator->()  
  46.     {  
  47.         return _ptr;  
  48.     }  
  49. private:  
  50.     T* _ptr;  
  51. };  
  52.   
  53. void Test1()  
  54. {  
  55.     AutoPtr<int> ap(new int(1));  
  56.     AutoPtr<int> ap1(ap);  
  57.     AutoPtr<int> ap2;  
  58.     ap2 = ap1;  
  59. }</span>  



赋值运算符存在问题:
(由此可知对于动态内存空间只能由一个智能指针来管理,从而避免下面的问题。





存在的问题:
问题①:这种将一块空间的权限完全交给别人的方法:

产生问题的是拷贝构造和赋值运算符重载函数。
当调用了拷贝构造或是赋值运算符的重载函数任意一个时:
假设调用了拷贝构造函数,我们的本意是用一个对象去构造一个与之一模一样的对象,可是结果呢,我们把自己给弄丢了,完全没有达到我们预期的目标。
所以当我们在上述代码中的Test1中调用了拷贝构造函数时,如果我们想要修改第一次构造出来的对象的内容时,会发现对象的资源已经被清理了,所以会导致程序崩溃。

问题②:先看如下示例:

[cpp] view plain copy
  1. <span style="font-size:18px;">#define _CRT_SECURE_NO_WARNINGS 1  
  2. #include<iostream>  
  3. using namespace std;  
  4.   
  5. template<class T>  
  6. class AutoPtr  
  7. {  
  8. public:  
  9.     AutoPtr(T* ptr = 0)//构造函数  
  10.         :_ptr(ptr)  
  11.     {  
  12.         ptr = NULL;  
  13.     }  
  14.   
  15.     AutoPtr(AutoPtr<T>& ap)//拷贝构造函数  
  16.         :_ptr(ap._ptr)  
  17.     {  
  18.         ap._ptr = NULL;  
  19.     }  
  20.   
  21.     AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值运算符重载  
  22.     {  
  23.         if (this != &ap)  
  24.         {  
  25.             if (_ptr)  
  26.             {  
  27.                 delete _ptr;  
  28.             }  
  29.             _ptr = ap._ptr;  
  30.             ap._ptr = NULL;  
  31.         }  
  32.         return *this;  
  33.     }  
  34.   
  35.     ~AutoPtr()//析构函数  
  36.     {  
  37.         if (_ptr)  
  38.         {  
  39.             delete _ptr;  
  40.             _ptr = NULL;  
  41.         }  
  42.     }  
  43.   
  44.     T& operator*()  
  45.     {  
  46.         return *_ptr;  
  47.     }  
  48.   
  49.     T* operator->()  
  50.     {  
  51.         return _ptr;  
  52.     }  
  53. private:  
  54.     T* _ptr;  
  55. };  
  56.   
  57. AutoPtr<int> Funtest()  
  58. {  
  59.     AutoPtr<int> ap(new int(1));  
  60.     return ap;  
  61. }  
  62.   
  63. void Test1()  
  64. {  
  65.     AutoPtr<int> ap(new int(1));  
  66.     AutoPtr<int> ap1(ap);  
  67.     AutoPtr<int> ap2;  
  68.     ap2 = ap1;  
  69.    <span style="color:#993399;"> </span><span style="color:#006600;">AutoPtr<int> ap4(Funtest());//返回值以值的形式返回,则为一个临时对象,  
  70.     //临时对象具有常性,所以在拷贝构造ap4时,拷贝构造函数的参数应该由const修饰</span><span style="color:#ff0000;">  
  71.      </span>  
  72. }  
  73. </span>  


问题③:

AutoPtr<int> ap(AutoPtr<int>(new int(1)))
//括号里是构造一个无名对象,无名对象,具有常性,和第②个问题一样,在拷贝构造ap时,拷贝构造函数的参数应该由const来修饰,还有一个问题就是,在vs2010下,编译器对其做了一些优化,本来这一条语句,应该是先调用构造函数构造匿名对象,然后由匿名对象去拷贝构造对象ap,但是由于在构造了匿名对象之后,又马上去拷贝构造对象,而且是在一条语句执行的,所以编译器对其进行了优化,只会调用构造函数,而不会去调用拷贝构造函数,将构造的无名对象值直接给了ap这个对象,所以在vs2010下程序并没有崩溃,而在Linux下编译时就会报出错误。

下面是我在Linux下测试时的代码:



编译错误:




总结:由上面的编译错误我们可以得知,这种由一个常性对象去拷贝构造一个Auto_ptr的想法是不现实的,所以才有了第三种情况。

实际上,实现方法三就是为了解决用一个临时右值对象去拷贝构造一个对象。


2.AutoPtr的第二种实现方法:

存在野指针的问题:
同样用示例来分析这个问题:
[cpp] view plain copy
  1. <span style="font-size:18px;">template<class T>  
  2. class AutoPtr  
  3. {  
  4. public:  
  5.     AutoPtr(T* ptr = 0)//构造函数  
  6.         :_ptr(ptr)  
  7.         , _owner(true)//当独占资源时将其设置为true  
  8.     {  
  9.         if (!_ptr)  
  10.         {  
  11.             _owner = false;  
  12.         }  
  13.     }  
  14.   
  15.     AutoPtr(const AutoPtr<T>& ap)//拷贝构造函数  
  16.         :_ptr(ap._ptr)  
  17.         , _owner(true)  
  18.     {  
  19.         ap._owner = false;  
  20.     }  
  21.   
  22.     AutoPtr& operator=(const AutoPtr<T>& ap)//赋值运算符重载  
  23.     {  
  24.         if (this != &ap)  
  25.         {  
  26.             delete _ptr;  
  27.             _owner = true;  
  28.             _ptr = ap._ptr;  
  29.             ap._owner = false;  
  30.         }  
  31.         return *this;  
  32.     }  
  33.   
  34.     ~AutoPtr()  
  35.     {  
  36.         if (_owner)  
  37.         {  
  38.             delete _ptr;  
  39.             _ptr = NULL;  
  40.             cout<<"~AutoPtr()"<<endl;  
  41.         }  
  42.     }  
  43.   
  44.     T& operator*()  
  45.     {  
  46.         return *_ptr;  
  47.     }  
  48.   
  49.     T* operator->()  
  50.     {  
  51.         return _ptr;  
  52.     }  
  53. private:  
  54.     T* _ptr;  
  55.     mutable bool _owner;//可被修改的  
  56. };  
  57.   
  58. void TestAutoPtr()  
  59. {  
  60.     /*AutoPtr<int> ap(new int(10)); 
  61.     AutoPtr<int> ap1(new int(20)); 
  62.     AutoPtr<int> ap2(ap1); 
  63.     AutoPtr<int> ap3; 
  64.     ap3 = ap;*/  
  65.     AutoPtr<int> ap4(AutoPtr<int>(new int(20)));  
  66.     if (true)  
  67.     {  
  68.         AutoPtr<int> ap5(ap4);  
  69.     }<span style="color:#009900;">//作用域结束之后ap5已被析构,空间已被释放</span>  
  70.    <span style="color:#ff0000;"> *ap4 = 10;//这时ap5与ap4共享一块空间,既然ap5已被释放,那么ap4对象维护的指针已成为野指针</span>  
  71. }  
  72.   
  73. int main()  
  74. {  
  75.     TestAutoPtr();  
  76.     return 0;  
  77. }</span>  

会发生内存泄漏,因为ap4与ap5共同管理一块空间,当ap5出了if语句的作用域后,已被析构,空间被回收,那么在下面在去访问ap4就有了问题,ap4已然成为了一个野指针。

③类型转化

c++标准库里的的auto_ptr的实现:
但还有是有缺陷:访问空指针的问题无法规避,也就是实现方法一存在的第一个问题

我先贴出标准库里的源码:

[cpp] view plain copy
  1. <span style="font-size:18px;">        // TEMPLATE CLASS auto_ptr  
  2. template<class _Ty>  
  3.     class auto_ptr;  
  4.   
  5. template<class _Ty>  
  6.     struct auto_ptr_ref  
  7.         {   // proxy reference for auto_ptr copying  
  8.     explicit auto_ptr_ref(_Ty *_Right)<span style="color:#009900;">//构造函数</span>  
  9.         : _Ref(_Right)  
  10.         {   // construct from generic pointer to auto_ptr ptr  
  11.         }  
  12.   
  13.     _Ty *_Ref;  // generic pointer to auto_ptr ptr  
  14.     };  
  15.   
  16. template<class _Ty>  
  17.     class auto_ptr  
  18.         {   // wrap an object pointer to ensure destruction  
  19. public:  
  20.     typedef auto_ptr<_Ty> _Myt;  
  21.     typedef _Ty element_type;  
  22. <span style="color:#009900;">//一般的构造函数</span>  
  23.     explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()  
  24.         : _Myptr(_Ptr)  
  25.         {   // construct from object pointer  
  26.         }  
  27. <span style="color:#009900;">//一般的拷贝构造函数</span>  
  28.     auto_ptr(_Myt& _Right) _THROW0()  
  29.         : _Myptr(_Right.release())  
  30.         {   // construct by assuming pointer from _Right auto_ptr  
  31.         }  
  32. <span style="color:#009900;">//带有隐式类型的构造函数</span>  
  33.     auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()  
  34.         {   // construct by assuming pointer from _Right auto_ptr_ref  
  35.         _Ty *_Ptr = _Right._Ref;  
  36.         _Right._Ref = 0;    // release old  
  37.         _Myptr = _Ptr;  // reset this  
  38.         }  
  39. <span style="color:#009900;">//类型转换</span>  
  40.     template<class _Other>  
  41.         operator auto_ptr<_Other>() _THROW0()  
  42.         {   // convert to compatible auto_ptr  
  43.         return (auto_ptr<_Other>(*this));  
  44.         }  
  45. <span style="color:#009900;">//对象的类型转换</span>  
  46.     template<class _Other>  
  47.         operator auto_ptr_ref<_Other>() _THROW0()  
  48.         {   // convert to compatible auto_ptr_ref  
  49.         _Other *_Cvtptr = _Myptr;   // test implicit conversion  
  50.         auto_ptr_ref<_Other> _Ans(_Cvtptr);  
  51.         _Myptr = 0; // pass ownership to auto_ptr_ref  
  52.         return (_Ans);  
  53.         }  
  54. <span style="color:#009900;">//一般的赋值运算符重载函数</span>  
  55.     template<class _Other>  
  56.         _Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()  
  57.         {   // assign compatible _Right (assume pointer)  
  58.         reset(_Right.release());  
  59.         return (*this);  
  60.         }  
  61.   
  62. /<span style="color:#009900;">/拷贝构造函数 </span>  
  63.     template<class _Other>  
  64.         auto_ptr(auto_ptr<_Other>& _Right) _THROW0()  
  65.         : _Myptr(_Right.release())  
  66.         {   // construct by assuming pointer from _Right  
  67.         }  
  68. <span style="color:#009900;">//一般的构造函数</span>  
  69.     _Myt& operator=(_Myt& _Right) _THROW0()  
  70.         {   // assign compatible _Right (assume pointer)  
  71.         reset(_Right.release());  
  72.         return (*this);  
  73.         }  
  74. <span style="color:#009900;">//带有类型转化的赋值运算符重载函数</span>  
  75.     _Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()  
  76.         {   // assign compatible _Right._Ref (assume pointer)  
  77.         _Ty *_Ptr = _Right._Ref;  
  78.         _Right._Ref = 0;    // release old  
  79.         reset(_Ptr);    // set new  
  80.         return (*this);  
  81.         }  
  82. <span style="color:#009900;">//析构函数</span>  
  83.     ~auto_ptr()  
  84.         {   // destroy the object  
  85.         delete _Myptr;  
  86.         }  
  87.   
  88.     _Ty& operator*() const _THROW0()  
  89.         {   // return designated value  
  90.  #if _ITERATOR_DEBUG_LEVEL == 2  
  91.         if (_Myptr == 0)  
  92.             _DEBUG_ERROR("auto_ptr not dereferencable");  
  93.  #endif /* _ITERATOR_DEBUG_LEVEL == 2 */  
  94.   
  95.         return (*get());  
  96.         }  
  97.   
  98.     _Ty *operator->() const _THROW0()  
  99.         {   // return pointer to class object  
  100.  #if _ITERATOR_DEBUG_LEVEL == 2  
  101.         if (_Myptr == 0)  
  102.             _DEBUG_ERROR("auto_ptr not dereferencable");  
  103.  #endif /* _ITERATOR_DEBUG_LEVEL == 2 */  
  104.   
  105.         return (get());  
  106.         }  
  107.   
  108.     _Ty *get() const _THROW0()  
  109.         {   // return wrapped pointer  
  110.         return (_Myptr);  
  111.         }  
  112. <span style="color:#009900;">//为了转交所有权</span>  
  113.     _Ty *release() _THROW0()  
  114.         {   // return wrapped pointer and give up ownership  
  115.         _Ty *_Tmp = _Myptr;  
  116.         _Myptr = 0;  
  117.         return (_Tmp);  
  118.         }  
  119. <span style="color:#009900;">//为了接收所有权</span>  
  120.     void reset(_Ty *_Ptr = 0)  
  121.         {   // destroy designated object and store new pointer  
  122.         if (_Ptr != _Myptr)  
  123.             delete _Myptr;  
  124.         _Myptr = _Ptr;  
  125.         }  
  126.   
  127. private:  
  128.     _Ty *_Myptr;    // the wrapped object pointer  
  129.     };  
  130. </span>  


示例分析:

[cpp] view plain copy
  1. <span style="font-size:18px;">#define _CRT_SECURE_NO_WARNINGS 1  
  2. #include<iostream>  
  3. using namespace std;  
  4. #include<memory>  
  5.   
  6. auto_ptr<int> FunTest()  
  7. {  
  8.     auto_ptr<int> ap1(new int(20));  
  9.     return ap1;//返回值为一个匿名对象  
  10. }  
  11.   
  12. void Test1()  
  13. {  
  14.     auto_ptr<int> ap1(new int(10));//构造函数  
  15.     auto_ptr<int> ap2(new int(20));//构造函数  
  16.     auto_ptr<int> ap3;  
  17.     ap3 = ap2;//赋值运算符重载  
  18.     auto_ptr<int> ap4(ap1);//拷贝构造  
  19.     auto_ptr<int> ap5(FunTest());//会发生类型转化 ,会先去调用这个类型转化函数operator auto_ptr_ref<_Other>(),</span>  
[cpp] view plain copy
  1. <span style="font-size:18px;">//然后调用构造函数auto_ptr(auto_ptr_ref<_Ty> _Right)。  
  2. }  
  3. </span>  

如果您还想知道标准库里究竟是怎样实现的,可以继续往下看,希望可以对您有所帮助。



源码分析:



























为了模拟一个一般指针,所以重载以下两个符号是为了使得智能指针可以像一般指针一样使用。



智能指针内封装的一个原生态指针:





二、ScopedPtr(独占空间--->防拷贝、防赋值)

其实在c++标准库里称为unique_ptr,很好理解了,因为AutoPtr就是因为转移资源,以及转交权限从而引发一系列的问题的,追根到底其实就是拷贝构造和赋值运算符重载函数导致的。所以这个智能指针就是防拷贝和赋值的)。

因为AutoPtr智能指针在拷贝构造和赋值运算符重载方面有些许问题,所以就有了ScopedPtr,既然拷贝构造和赋值运算符重载会引发一些问题,那么是不是可以不允许它拷贝和赋值呢?

既然拷贝和赋值容易出现问题,那么这种智能指针就不允许拷贝和赋值。
解决上述问题的方法:

实现这种机制的方法有三种:
1)将拷贝构造函数和赋值运算符重载函数的声明写成公有的,但是对这两个函数不进行定义。
2)将拷贝构造函数和赋值运算符重载函数在类型直接实现,但是将它们的访问限定符设定为私有的。
3)将拷贝构造函数和赋值运算符重载函数的声明写成私有的,但是对这两个函数不进行定义。

分析上述三种方法:
第一种:如果将其声明为公有的,那么如果有其他人在类外对你的拷贝构造和赋值运算符重载函数进行实现,那么还是没有达到防拷贝、防赋值的要求。--->pass掉
第二种:个人觉得,既然都已经不允许拷贝和赋值了,为什么还要多此一举的写出其实现方法呢?所以呢----->pass掉
所以:就第三种方法觉得合适。

在这里我只贴出第三种方法的代码:


[cpp] view plain copy
  1. <span style="font-size:18px;">//防拷贝、防赋值  
  2. template<class T>  
  3. class ScopedPtr  
  4. {  
  5. public :  
  6.     ScopedPtr(T* ptr)//构造函数  
  7.         :_ptr(ptr)  
  8.     {}  
  9.     ~ScopedPtr()//析构函数  
  10.     {  
  11.         if (NULL != _ptr)  
  12.         {  
  13.             delete _ptr;  
  14.             _ptr = NULL;  
  15.         }  
  16.     }  
  17.   
  18.     T& operator*()  
  19.     {  
  20.         return *_ptr;  
  21.     }  
  22.   
  23.     T* operator->()  
  24.     {  
  25.         return _ptr;  
  26.     }  
  27. private :  
  28.     ScopedPtr(const ScopedPtr& ap);//拷贝构造函数声明  
  29.     ScopedPtr& operator=(const ScopedPtr& ap);//赋值运算符重载函数声明  
  30.     T* _ptr;  
  31. };  
  32.   
  33. void Test1()  
  34. {  
  35.     ScopedPtr<int> sp1(new int(10));  
  36.     *sp1 = 20;  
  37. }</span>  

scoped_array//管理数组
boost库里面的,c++标准库由于已经有相似功能的vector,所以并未将其此加入)
[cpp] view plain copy
  1. <span style="font-size:18px;">//管理数组(防拷贝、防赋值)  
  2. template<class T>  
  3. class ScopedArray  
  4. {  
  5. public:  
  6.     ScopedArray(T* ptr = 0)//构造函数  
  7.         :_ptr(ptr)  
  8.     {}  
  9.     ~ScopedArray()//析构函数  
  10.     {  
  11.         if (NULL != _ptr)  
  12.         {  
  13.             delete[] _ptr;  
  14.             _ptr = NULL;  
  15.         }  
  16.     }  
  17. //基本操作  
  18.     T& operator*()  
  19.     {  
  20.         return *_ptr;  
  21.     }  
  22. //基本操作  
  23.     T* operator->()  
  24.     {  
  25.         return _ptr;  
  26.     }  
  27. //基本操作  
  28.     T& operator[](size_t index)  
  29.     {  
  30.         return _ptr[index];  
  31.     }  
  32. private:  
  33.     ScopedArray(const ScopedArray<T>& ap);  
  34.     ScopedArray& operator=(const ScopedArray<T>& ap);  
  35.     T* _ptr;  
  36. };</span>  

总结:c++标准库里的智能指针只能管理单个对象的动态空间,而不能让其管理一段连续空间,例如:动态开辟的数组的空间。

auto_ptr无论什么时候都不要使用
scoped_ptr是对auto_ptr所存在的问题的一个解决。
所以一般面试时,没有特别指定让你实现哪个智能指针,最好写出这个,因为这个最简单呀,千万不要写出auto_ptr,这个智能指针存在缺陷!

虽然c++标准库里面加入了auto_ptr智能指针,但是还是不要使用它,c++标准库里仍然保留它,应该是为了向前兼容。
因为既然已经加入了标准库,那么肯定会有程序员使用的,所以还是不能随意废弃掉。

后续我还会继续总结关于shared_ptr的实现细节。



题外话:

因为刚开始接触智能指针,自身能力不足,所以哪里写的有问题的欢迎大家提出来。
共同进步!
每天进步一点点!

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

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

相关文章

多重继承之虚继承(主要是为了解决产生的数据冗余问题)

虚继承 是面向对象编程中的一种技术&#xff0c;是指一个指定的基类&#xff0c;在继承体系结构中&#xff0c;将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。形式&#xff1a;在继承定义中包含了virtual关键字的继承关系&#xff0c;如下图中&#xff0c;类A就…

/proc 虚拟文件系统(实例)

Linux下有一个神奇的目录/proc&#xff0c;经常会运行 cat /proc/cpuinfo 命令查看cpu信息&#xff0c;/proc下的确有cpuinfo文件&#xff0c;但是这个文件不是物理存在的&#xff0c;是软件虚拟出来的&#xff0c;与普通文件不同&#xff0c;该文件是动态的。通过/proc可以实现…

malloc,calloc,realloc

与堆操作相关的两个函数 malloc #include<stdio.h> #include<stdlib.h> #include<string.h>int main() {char *p malloc(10); //内存随机&#xff0c;未做处理int i;for(i 0; i < 10: i){printf(“%d “,p[i]);} free(p);return 0; } 运行结果&…

Linux内核线程kernel thread详解--Linux进程的管理与调度

内核线程为什么需要内核线程Linux内核可以看作一个服务进程(管理软硬件资源&#xff0c;响应用户进程的种种合理以及不合理的请求)。 内核需要多个执行流并行&#xff0c;为了防止可能的阻塞&#xff0c;支持多线程是必要的。 内核线程就是内核的分身&#xff0c;一个分身可以处…

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

在2.6.24之后这个结构体有了较大的变化&#xff0c;此处先说一说2.6.16版本的sk_buff&#xff0c;以及解释一些问题。一、先直观的看一下这个结构体~~~~~~~~~~~~~~~~~~~~~~在下面解释每个字段的意义~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

最常用的设计模式---适配器模式(C++实现)

适配器模式属于结构型的设计模式&#xff0c;它是结构型设计模式之首&#xff08;用的最多的结构型设计模式&#xff09;。 适配器设计模式也并不复杂&#xff0c;适配器它是主要作用是将一个类的接口转换成客户希望的另外一个接口这样使得原本由于接口不兼容而不能一起工作的那…

c++简单线程池实现

线程池&#xff0c;简单来说就是有一堆已经创建好的线程&#xff08;最大数目一定&#xff09;&#xff0c;初始时他们都处于空闲状态&#xff0c;当有新的任务进来&#xff0c;从线程池中取出一个空闲的线程处理任务&#xff0c;然后当任务处理完成之后&#xff0c;该线程被重…

Linux 打印可变参数日志

实现了传输进去的字符串所在的文档&#xff0c;函数和行数显示功能。 实现了将传入的可变参数打印到日志功能。 #include<stdio.h> #include<stdarg.h> #include<string.h>const char * g_path "/home/exbot/wangqinghe/log.txt"; #define LOG(fm…

C++强化之路之线程池开发整体框架(二)

一.线程池开发框架 我所开发的线程池由以下几部分组成&#xff1a; 1.工作中的线程。也就是线程池中的线程&#xff0c;主要是执行分发来的task。 2.管理线程池的监督线程。这个线程的创建独立于线程池的创建&#xff0c;按照既定的管理方法进行管理线程池中的所有线程&#xf…

vfprintf()函数

函数声明&#xff1a;int vfprintf(FILE *stream, const char *format, va_list arg) 函数参数&#xff1a; stream—这是指向了FILE对象的指针&#xff0c;该FILE对象标识了流。 format—c语言字符串&#xff0c;包含了要被写入到流stream中的文本。它可以包含嵌入的format标签…

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决&#xff08;全&#xff09;在socket网络程序中&#xff0c;TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程&#xff0c;收发两端&#xff08;客户端和服务器端&#xff09;都要有成对的socket&#xff0c;因此&#xff0c;发送端为了将…

UML类图符号 各种关系说明以及举例

UML中描述对象和类之间相互关系的方式包括&#xff1a;依赖&#xff0c;关联&#xff0c;聚合&#xff0c;组合&#xff0c;泛化&#xff0c;实现等。表示关系的强弱&#xff1a;组合>聚合>关联>依赖 相互间关系 聚合是表明对象之间的整体与部分关系的关联&#xff0c…

ESP传输模式拆解包流程

一、 ESP简介ESP&#xff0c;封装安全载荷协议(Encapsulating SecurityPayloads)&#xff0c;是一种Ipsec协议&#xff0c;用于对IP协议在传输过程中进行数据完整性度量、来源认证、加密以及防回放攻击。可以单独使用&#xff0c;也可以和AH一起使用。在ESP头部之前的IPV4…

linux内核netfilter模块分析之:HOOKs点的注册及调用

1: 为什么要写这个东西?最近在找工作,之前netfilter 这一块的代码也认真地研究过&#xff0c;应该每个人都是这样的你懂 不一定你能很准确的表达出来。 故一定要化些时间把这相关的东西总结一下。 0&#xff1a;相关文档linux 下 nf_conntrack_tuple 跟踪记录 其中可以根据内…

网络抓包工具 wireshark 入门教程

Wireshark&#xff08;前称Ethereal&#xff09;是一个网络数据包分析软件。网络数据包分析软件的功能是截取网络数据包&#xff0c;并尽可能显示出最为详细的网络数据包数据。Wireshark使用WinPCAP作为接口&#xff0c;直接与网卡进行数据报文交换。网络管理员使用Wireshark来…

结构体中指针

结构体中带有指针的情况 #include<stdio.h>struct man {char *name;int age; };int main() {struct man m {"tom",20};printf("name %s, age %d\n",m.name,m.age);return 0; } 运行结果&#xff1a; exbotubuntu:~/wangqinghe/C/20190714$ gcc st…

python使用opencv提取视频中的每一帧、最后一帧,并存储成图片

提取视频每一帧存储图片 最近在搞视频检测问题&#xff0c;在用到将视频分帧保存为图片时&#xff0c;图片可以保存&#xff0c;但是会出现(-215:Assertion failed) !_img.empty() in function cv::imwrite问题而不能正常运行&#xff0c;在检查代码、检查路径等措施均无果后&…

线程间通信之eventfd

线程间通信之eventfd man手册中的解释&#xff1a; eventfd()创建了一个“eventfd对象”&#xff0c; 通过它能够实现用户态程序间(我觉得这里主要指线程而非进程)的等待/通知机制&#xff0c;以及内核态向用户态通知的机制&#xff08;未考证&#xff09;。 此对象包含了一个…

定时器timerfd

1.为什么要加入此定时器接口 linux2.6.25版本新增了timerfd这个供用户程序使用的定时接口&#xff0c;这个接口基于文件描述符&#xff0c;当超时事件发生时&#xff0c;该文件描述符就变为可读。我首次接触这个新特性是在muduo网络库的定时器里看到的&#xff0c;那么新增一个…

timerfd与epoll

linux timerfd系列函数总结 网上关于timerfd的文章很多&#xff0c;在这儿归纳总结一下方便以后使用&#xff0c;顺便贴出一个timerfd配合epoll使用的简单例子 一、timerfd系列函数 timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符&#xff0c;通过文…