剖析C++标准库智能指针(std::auto_ptr)

2023-10-30

1.Do you Smart Pointer?

      Smart Pointer,中文名:智能指针, 舶来品?
      不可否认,资源泄露(resource leak)曾经是C++程序的一大噩梦.垃圾回收
      机制(Garbage Collection)一时颇受注目.然而垃圾自动回收机制并不能
      满足内存管理的即时性和可视性,往往使高傲的程序设计者感到不自在.
      况且,C++实现没有引入这种机制.在探索中,C++程序员创造了锋利的
      "Smart Pointer".一定程度上,解决了资源泄露问题.

      也许,经常的,你会写这样的代码:
      //x拟为class:

//   class x{
      
//             public:        
      
//                    int m_Idata;
      
//             public:
      
//                    x(int m_PARAMin):m_Idata(m_PARAMin){}
      
//                    void print(){ cout<<m_Idata<<endl; }
      
//             .....
      
//             }
      
//
       void  fook() {
      x
* m_PTRx = new A(m_PARAMin);
      m_PTRx
->DoSomething();     //#2
      delete m_PTRx;
      }


            是的,这里可能没什么问题.可在复杂、N行、m_PTRclassobj所指对象生命周
      期要求较长的情况下,你能保证你不会忘记delete m_PTRclassobj吗?生活中,
      我们往往不应该有太多的口头保证,我们需要做些真正有用的东西.还有一个
      更敏感的问题:异常.假如在#2方法执行期异常发生,函数执行终止,那么new
      出的对象就会泄露.于是,你可能会说:那么就捕获异常来保证安全性好了.
      你写这样的程式:

     void  fook() {
      A
* m_PTRx = new x(m_PARAMin);
      
try{
          m_PTRx
->DoSomething();
      }

      
catch(..){
          delete m_PTRx;
          
throw;
      }

      delete m_PTRx;
      }

      哦!天哪!想象一下,你的系统,是否会象专为捕获异常而设计的.

      一天,有人给你建议:"用Smart Pointer,那很安全.".你可以这样重写你的程序:
    

       void  fook() {
      auto_ptr
<x> m_SMPTRx(new x(m_PARAMin));
      m_SMPTRx
->DoSomething();
      }

 

      OK!你不太相信.不用delete吗?
      是的.不用整天提心吊胆的问自己:"我全部delete了吗?",而且比你的delete
      策略更安全.

      然后,还有人告诉你,可以这样用呢:

 

 ok1.
      auto_ptr
< x >  m_SMPTR1( new  x(m_PARAMin)); 
      auto_ptr
< x >  m_SMPTR2(m_SMPTR1);   // #2
      May be you can code # 2  like  this  :
          auto_ptr
< x >  m_SMPTR2;
          m_SMPTR2 
=  m_SMPTR1;      
      ok2.
      auto_ptr
< int >  m_SMPTR1( new   int ( 32 ));
      
      ok3.
      auto_ptr
< int >  m_SMPTR1;
      m_SMPTR1 
=  auto_ptr < int > ( new   int ( 100 ));
      也可以:
      auto_ptr
< int >  m_SMPTR1(auto_ptr < int > ( new   int ( 100 )));
      
      ok4.
      auto_ptr
< x >  m_SMPTR1( new  x(m_PARAMin));
      m_SMPTR1.reset(
new  x(m_PARAMin1));
      
      ok5.
      auto_ptr
< x >  m_SMPTR1( new  x(m_PARAMin));
      auto_ptr
< x >  m_SMPTR2(m_SMPTR.release());
      cout
<< ( * m_SMPTR2).m_Idata << endl;  
      
      ok6.
      auto_ptr
< int >  fook() {
      
return auto<int>(new int(100));
      }

 


           ok7.............and so on
      
      但不可这样用:
      
      

no1.   
      
char *  chrarray  =   new   char [ 100 ];
      strcpy(chrarray,
" I am programming. " );
      auto_ptr
< char *>  m_SMPTRchrptr(chrarray);
      
// auto_ptr并不可帮你管理数组资源     
       
      no2.
      vector
< auto_ptr < x >>  m_VECsmptr;
      m_VECsmptr.push_back(auto_ptr
< int > ( new   int ( 100 )));
      
// auto_ptr并不适合STL内容.
       
      no3.
      
const  auto_ptr < x >  m_SMPTR1( new  x( 100 ));
      auto_ptr
< x >  m_SMPTR( new  x( 200 ));
      
      no4.
      x m_OBJx(
300 );
      auto_ptr
< x >  m_SMPTR( & m_OBJx);
      
      no5
      x
*  m_PTR  =   new  x( 100 );
      auto_ptr
< x >  m_SMPTR  =  m_pTR;
      


      no6..........and so on

      预先提及所有权的问题,以便下面带着疑问剖析代码?

 

      power1.
      auto_ptr
< x >  m_SMPTR1( new  x( 100 ));
      auto_ptr
< x >  m_SMPTR2  =  m_SMPTR1;
      m_SMPTR2
-> print();
      
// 输出:100.
      m_SMPTR1 -> print();
      
// !! 非法的.

      power2.
      auto_ptr
< x >  m_SMPTR( new  x( 100 ));
      
      auto_ptr
< x >  returnfun(auto_ptr < x >  m_SMPTRin) {
      
return m_SMPTRin;
      }

      
      auto_ptr
< x >   =  returnfun(m_SMPTR);   // #5

 

      //在上面的#5中,我要告诉你对象所有权转移了两次.
      //什么叫对象所有权呢?
   
    2. std::auto_ptr的设计原理
       
      上面的一片正确用法,它们在干些什么?
            一片非法,它们犯了什么罪?
            一片什么所有权转移,它的内部机智是什么?
      哦!一头雾水?下面我们就来剖析其实现机制.
      基础知识:
              a.智能指针的关键技术:在于构造栈上对象的生命期控制
                堆上构造的对象的生命期.因为在智能指针的内部,存储
                着堆对象的指针,而且在构析函数中调用delete行为.
                大致机构如下:
                x* m_PTRx = new x(100);//#1
                template<typename T>
                auto_ptr{
                private:
                T* m_PTR;//维护指向堆对象的指针,在auto_ptr定位后     
                ....     //它应该指向#1构造的对象,即拥有所有权.
                ~auto(){ delete m_PTR; }
                ....
                }
             b.所有权转移之说
               上面曾有一非法的程式片段如下:
               auto_ptr<x> m_SMPTR1(new x(100));
               auto_ptr<x> m_SMPTR2 = m_SMPTR1;
               m_SMPTR2->print();
               //输出:100.
               m_SMPTR1->print();
               //!! 非法的.
               按常理来说,m_SMPTR->print();怎么是非法的呢?
               那是因为本来,m_SMPTR1维护指向new x(100)的指针,
               可是m_SMPTR2 = m_SMPTR1;auto_ptr内部机制使得m_SMPTR1将对象的地址
               传给m_SMPTR2,而将自己的对象指针置为0.
               那么自然m_SMPTR->print();失败.
               这里程序设计者要负明显的职责的.
               那么auto_ptr为什么采取这样的策略:保证所有权的单一性.
                                               亦保证了系统安全性.
               如果多个有全权的auto_ptr维护一个对象,那么在你消除一个
               auto_ptr时,将导致多个auto_ptr的潜在危险.
      
       下面我们以SGI-STL的auto_ptr设计为样本(去掉了无关分析的宏),来剖析其原理.

 

# 1   template  < class  _Tp >   class  auto_ptr  {
       #
2  private:
       #
3  _Tp* _M_ptr;  //定义将维护堆对象的指针

       #
4  public:
       #
5  typedef _Tp element_type;  //相关类型定义
       #6  explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
       #
7  auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
       #
8  template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
                                                 : _M_ptr(__a.release()) 
{}
           
//#6、#7、#8是auto_ptr构造函数的三个版本.
           
//#6注释:传入对象的指针,构造auto_ptr.explicit关键字:禁止隐式转换.
           
//        这就是ok2正确,而no5(隐式转换)错误的原因.
           
//#7注释:拷贝构造函数.
           
//        传入auto_ptr实例,构造auto_ptr. ok1、ok3使用了这个构造式.
           
//        它是一个很关键的构造函数,在具体情况下,我们再分析
           
//#8注释:auto_ptr的模板成员,可在继承对象重载的基础上,实现特殊功能.
           
//   
           
//   举例:
           
//   class A{ public: 
           
//          virtual void fook(){cout<<"I am programming"<<endl;
           
//          /*..........*/                                   }; 
           
//   class B : public A {
           
//          virtual void fook(){ cout<<"I am working"<<endl;
           
//         /*...........*/                                  };  
           
//   auto_ptr<A> m_SMPTRa(new A(33));//实质:
           
//   auto_ptr<B> m_SMPTRb(m_SMPTRa); //基类的指针可以赋给派生类的指针          
           
//              
           
//   auto_ptr<B> m_SMPTRb(new B(44));//实质:
           
//   auto_ptr<A> m_SMPTRa(m_SMPTRb); //派生类的指针不可赋给基类的指针
           
//       
           
//   auto_ptr<A> m_SMPTRa(new B(33));  // ok!  
           
//   m_SMPTRa->fook()将调用派生类B的fook()
           
//   m_SMPTRa->A::fook()将调用基类A的fook()
           
//    
           
//   auto_ptr<B> m_SMPTRb(new A(33));  // wrong!
           
//   
           
//   
       #9  auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
       #
10 if (&__a != this{ delete _M_ptr;  _M_ptr = __a.release(); }
       #
11 return *this;
       #
12 }

         
       #
13 template <class _Tp1>
       #
14 auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
       #
15 if (__a.get() != this->get()) { delete _M_ptr; _M_ptr = __a.release(); }
       #
16 return *this;
       #
16 }
  
          
//
          
// #9~~#16 两个版本的指派函数.
          
//         delete _M_ptr; 在指派前,销毁原维护的对象.
          
//         _a.release() ; release操作,详细代码参见#20~~#23.
          
//                        用于*this获得被指派对象,
          
//                        且将原维护auto_ptr置空.
          
//     no3使用了第一种指派.
          
//     而权限转移正是_a.release()的结果.
          
       #
17 ~auto_ptr() __STL_NOTHROW { delete _M_ptr; }
          
//构析函数.消除对象.注意这里对对象的要求!
          
       #
17 _Tp& operator*() const __STL_NOTHROW {  return *_M_ptr; }
       #
18 _Tp* operator->() const __STL_NOTHROW return _M_ptr;  }
       #
19 _Tp* get() const __STL_NOTHROW return _M_ptr; }
         
//
         
//  操作符重载.
         
// #17注释:提领操作(dereference),获得对象. 见ok5用法.
         
// #18注释:成员运算符重载,返回对象指针.
         
// #19注释:普通成员函数.作用同于重载->运算符
         
//
       #20 _Tp* release() __STL_NOTHROW {
       #
21 _Tp* __tmp = _M_ptr;
       #
22 _M_ptr = 0;
       #
23 return __tmp;                }

         
//上面已经详解      
 
       #
24 void reset(_Tp* __p = 0) __STL_NOTHROW {
       #
25 delete _M_ptr;
       #
26 _M_ptr = __p;                          }

         
//
         
//传入对象指针,改变auto_ptr维护的对象
         
//       且迫使auto_ptr消除原来维护的对象
         
//       见ok3用法.

         
// According to the C++ standard, these conversions are required.  Most
         
// present-day compilers, however, do not enforce that requirement---and, 
         
// in fact, most present-day compilers do not support the language 
         
// features that these conversions rely on.
         


                //下面这片段用于类型转化,目前没有任何编译器支持
         //具体技术细节不诉.         

 

         

#ifdef __SGI_STL_USE_AUTO_PTR_CONVERSIONS

      #
27   private :
      #
28  template < class  _Tp1 >  
      #
29   struct  auto_ptr_ref  { _Tp1* _M_ptr; auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
                             }
;

      #
30   public :
      #
31  auto_ptr(auto_ptr_ref < _Tp >  __ref) __STL_NOTHROW
                               : _M_ptr(__ref._M_ptr) 
{}
      #
32  template  < class  _Tp1 >  
      #
33   operator  auto_ptr_ref < _Tp1 > () __STL_NOTHROW 
      #
34   return auto_ptr_ref<_Tp>(this->release()); }
      #
35  template  < class  _Tp1 >   operator  auto_ptr < _Tp1 > () __STL_NOTHROW
      #
36   return auto_ptr<_Tp1>(this->release()); }
      #
37   #endif  /* __SGI_STL_USE_AUTO_PTR_CONVERSIONS */
      #
38  };

      
      OK!就是这样了.
      正如上面原理介绍处叙说,
      你需要正视两大特性:
      1.构造栈对象的生命期控制堆上构造的对象的生命期
      2.通过release来保证auto_ptr对对象的独权.
      
     在我们对源码分析的基础上,重点看看:
     no系列错误在何处?
     no1.
         我们看到构析函数template<class _Tp>
                         ~auto_ptr() _STL_NOTHROW
                        { delete _M_ptr; }
         所以它不能维护数组,
         维护数组需要操作:delete[] _M_ptr;
     no2.
        先提部分vector和auto_ptr代码:
        a.提auto_ptr代码
          
        

auto_ptr(auto_ptr &  __a) __STL_NOTHROW : _M_ptr(__a.release())  {}

        
        b.提vector代码
         


          Part1:
          
void  push_back( const  _Tp &  __x)  {
          
if (_M_finish != _M_end_of_storage) {
          construct(_M_finish, __x);
          
++_M_finish;
          }

          
else
         _M_insert_aux(end(), __x);
          }

        
         Part2:
         template 
< class  _T1,  class  _T2 >
         inline 
void  construct(_T1 *  __p,

         
// ++++++++++++++++++++++++++++++++ 
         
//          const _T2& __value) { +
         
// ++++++++++++++++++++++++++++++++
         
//   new (__p) _T1(__value);      +
         
// ++++++++++++++++++++++++++++++++

         }
         
         Part3.
         template 
< class  _Tp,  class  _Alloc >
         
void  
         vector
< _Tp, _Alloc > ::_M_insert_aux
         (iterator __position,

          
// ++++++++++++++++++++++++++++++++ 
          
//         const _Tp& __x)       ++
          
// ++++++++++++++++++++++++++++++++   
 
         
{
         
if (_M_finish != _M_end_of_storage) {
         construct(_M_finish, 
*(_M_finish - 1));
         
++_M_finish;

         
//++++++++++++++++++++++++++++++++
         
//     _Tp __x_copy = __x;       +
         
//++++++++++++++++++++++++++++++++

         copy_backward(__position, _M_finish 
- 2, _M_finish - 1);
         
*__position = __x_copy;
         }

         
else {
         
const size_type __old_size = size();
         
const size_type __len = __old_size != 0 ? 2 * __old_size : 1;
         iterator __new_start 
= _M_allocate(__len);
         iterator __new_finish 
= __new_start;
         __STL_TRY 
{
         __new_finish 
= uninitialized_copy
         (_M_start, __position, __new_start);
         construct(__new_finish, __x);
         
++__new_finish;
         __new_finish 
= uninitialized_copy
        (__position, _M_finish, __new_finish);
        }

        __STL_UNWIND((destroy(__new_start,__new_finish), 
                  _M_deallocate(__new_start,__len)));
       destroy(begin(), end());
       _M_deallocate(_M_start, _M_end_of_storage 
- _M_start);
       _M_start 
= __new_start;
       _M_finish 
= __new_finish;
       _M_end_of_storage 
= __new_start + __len;
       }

       }

 

       从提取的vector代码,Part1可看出,push_back的操作行为.
       兵分两路,可是再向下看,你会发现,无一例外,都
       通过const _Tp& 进行拷贝行为,那么从auto_ptr提出的片段就
       派上用场了. 
       可你知道的,auto_ptr总是坚持对对象的独权.那必须修改
       原来维护的对象,而vector行为要求const _Tp&,这样自然会产生
       问题.一般编译器是可以发觉这种错误的.

       其实,STL所有的容器类都采用const _Tp&策略.
  
       //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      + 看了sutter和Josuttis的两篇文章中,都提及:                    +
      + STL容器不支持auto_ptr原因在于copy的对象只是获得所有权的对象, +
      + 这种对象不符合STL的要求.可是本人总感觉即时不是真正的复制对象,+
      + 但我用vector<auto_ptr<x> >的目的就在于维护对象,并不在乎      +
      + 所谓的完全对象.而且我用自己写的Smart Pointer配合STL容器工作, +
      + 很正常.那需要注意的仅仅是const问题.                          +
      +                                                              +
      //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

     no3.
        这个也是auto_ptr隐含的所有权问题引起的.
        const auto_ptr不允许修改.
        随便提及:const对象不代表对象一点不可以改变.
                  在两种const语义下,都有方法修改对象或对象内部指针维护的对象
                 或其它资源.
     no4.
        再看auto_ptr的构析函数.
        delete不可以消除栈上资源.

     no5.
        依赖传入对象指针的构造函数被声明为explicit,禁止隐式转换.

    
    3.auto_ptr高级使用指南
      
      a.类成员auto_ptr,禁止构造函数以构建"完全对象"

 

Programme1:
        
struct  Structx {
               
int m_Idata;
               
char m_CHRdata;
               
/* and so on */
        }
;
        出于对象编程的理念,
        我们将Structx打造成包裹类:
        
class  StructWrapper {
        
private:
        Structx
* m_STRTxptr;
        
public:
        StructWrapper():m_STRTxptr(
new Structx){}
        
~StructWrapper(){delete m_SMRTxptr; }
        
public:
        
void Soperator1()/* 针对Structx对象的特性操作 */}
        
void Soperator2()/* 针对Structx对象的特性操作 */}        
        
/*  and so on */
        }

        
        Programme2:
        
class  StructWrapper {
        
private:
        auto_ptr
<Structx> m_SMPTRx;
        
public:
        StructWrapper():m_SMPTRAx(
new Structx){}
        
public:
        
void Soperator1()/* 针对Structx对象的特性操作 */}
        
void Soperator2()/* 针对Structx对象的特性操作 */}        
        
/*  and so on */
        }

        
        Programme3:
        StructWrapper::StructWrapper(
const  StructWrapper &  other)
        : M_SMPTRx(
new  Struct( * other.m_SMPTRx))  { }
        StructWrapper
&  StructWrapper:: operator = ( const  StructWrapper  & other) {
        
*m_SMPTRx = *other.m_SMPTRx;
        }
;


                处于对构建于堆中的对象(new Structx)智能维护的需要.
        我们将programme1改造为programme2:
        不错,对象是可以智能维护了.
        对于包裹类(StructWrapper)你是否会有这样的构造或指派操作:
         StructWrapper m_SMPTRWrapper2(m_SMPTRWrapper1);
       
         StructWrapper mSMPTRWrapper2 = m_SMPTRWrapper1; 
         那么请注意:
         当你坦然的来一个:M_SMPTRWrapper1->Soperator1();的时候,
         系统崩溃了.
         不必惊讶,所有权还是所有权问题.
         问一下自己:当programme2默认拷贝构造函数作用时,又调用了auto_ptr的
         默认构造函数,那么auto_ptr所有的默认行为都遵循独权策略.对,就这样.
         m_SMPTRWrapper1的对象所有权转移给了m_SMPTRWrapper2.
         M_SMPTRWrapper1->Soperator1();那么操作变成了在NULL上的.
         哦!系统不崩溃才怪.
         那么你需要想,programme3那样利用auto_ptr的提领操作符自己的
         构造"完全对象".

       b.利用const关键字,防止不经意的权限转移
         
         从上面的叙述,你可看出,所有权转移到处可以酿成大祸.
         而对于一般应用来说,独权又是很好的安全性策略.
         那么我们就用const来修饰auto_ptr,禁止不经意的错误.
        
         当然上面提及:并不代表auto_ptr是不可修改的.
         处于需要,从两种const语义,你都可实现修改.

         然,你还希望在函数传入传出auto_ptr那么你可传递auto_ptr的引用,
         那就万无一失了: void fook(const auto_ptr<x>& m_PARAMin);
         在返回后赋予其它时,使用引用是不行的.你得用指针.
         因为引用无论作为lvalue还是rvaluev,都会调用构造或指派函数.


    4.你是否觉得std::auto_ptr还不够完美
      
      在实践中,std::auto_ptr能满足你的需求吗?           
 
      Andrei Alexandrescu在一篇文章中,提及:有关Smart Pointer的技术就像
      巫术.Smart Pointer作为C++垃圾回收机制的核心,它必须足够强大的、具有工业强度和安全性.
      但为了可一劳永逸我们还需要披荆斩棘继续探索.

      下面在需求层面上,我们思索一下我们的智能指针还需要些什么?
 
        a. std::auto_ptr 能够处理数组吗?我们可以用智能指针来管理其它的资源吗?
           譬如一个线程句柄、一个文件句柄 and so on !
        b. 对于我们的对象真的永远实行独权政策吗?
        c. Our 智能指针还需要在继承和虚拟层面上发挥威力 !
        d. 往往,需要扩展Our 智能指针的功能成员函数来满足动态的需要 !
        e. 也许,你需要的还很多.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

剖析C++标准库智能指针(std::auto_ptr) 的相关文章

  • Tensorflow 中的自定义资源

    由于某些原因 我需要为 Tensorflow 实现自定义资源 我试图从查找表实现中获得灵感 如果我理解得好的话 我需要实现3个TF操作 创建我的资源 资源的初始化 例如 在查找表的情况下填充哈希表 执行查找 查找 查询步骤 为了促进实施 我
  • 将处理后的图形绘制到另一个图形中

    我想将一个经过处理的图形绘制到另一个图形中 I have two graphics var gHead Graphics FromImage h var gBackground Graphics FromImage b Transform
  • MEX 文件中的断言导致 Matlab 崩溃

    我正在使用mxAssert 宏定义为matrix h在我的 C 代码中 mex 可以完美编译 当我调用的 mex 代码中违反断言时 该断言不会导致我的程序崩溃 而是导致 Matlab 本身崩溃 我错过了什么吗 这是有意的行为吗 当我查看 M
  • 在 C++ 中分割大文件

    我正在尝试编写一个程序 该程序接受一个大文件 任何类型 并将其分成许多较小的 块 我想我已经有了基本的想法 但由于某种原因我无法创建超过 12 kb 的块大小 我知道谷歌等上有一些解决方案 但我更感兴趣的是了解这个限制的根源是什么 然后实际
  • 当我单击 C# 中的“取消”按钮时重定向到新页面(Web 部分)

    Cancel button tc new TableCell btnCancel new Button btnCancel Text Cancel btnCancel Click new EventHandler btnCanel Clic
  • Blazor 与 Razor

    随着 Blazor 的发明 我想知道这两种语言之间是否存在显着的效率 无论是在代码创建方面还是在代码的实际编译 执行方面 https github com SteveSanderson Blazor https github com Ste
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • 如何在 VS 中键入时显示方法的完整文档?

    标题非常具有描述性 是否有任何扩展可以让我看到我正在输入的方法的完整文档 我想查看文档 因为我可以在对象浏览器中看到它 其中包含参数的描述和所有内容 而不仅仅是一些 摘要 当然可以选择查看所有覆盖 它可能是智能感知的一部分 或者我不知道它并
  • C++11 函数局部静态 const 对象的线程安全初始化

    这个问题已在 C 98 上下文中提出 并在该上下文中得到回答 但没有明确说明有关 C 11 的内容 const some type create const thingy lock my lock some mutex static con
  • 单元测试失败,异常代码为 c0000005

    我正在尝试使用本机单元测试项目在 Visual Studios 2012 中创建单元测试 这是我的测试 TEST METHOD CalculationsRoundTests int result Calculations Round 1 0
  • C# 创建数组的数组

    我正在尝试创建一个将使用重复数据的数组数组 如下所示 int list1 new int 4 1 2 3 4 int list2 new int 4 5 6 7 8 int list3 new int 4 1 3 2 1 int list4
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • 如何检测 C# 中该字典键是否存在?

    我正在使用 Exchange Web 服务托管 API 和联系人数据 我有以下代码 即功能性的 但并不理想 foreach Contact c in contactList string openItemUrl https service
  • Fluent NHibernate 日期时间 UTC

    我想创建一个流畅的 nhibernate 映射来通过以下方式映射 DateTime 字段 保存时 保存 UTC 值 读取时 调整为本地时区值 实现此映射的最佳方法是什么 就我个人而言 我会将日期存储在 UTC 格式的对象中 然后在读 写时在
  • 我应该在应用程序退出之前运行 Dispose 吗?

    我应该在应用程序退出之前运行 Dispose 吗 例如 我创建了许多对象 其中一些对象具有事件订阅 var myObject new MyClass myObject OnEvent OnEventHandle 例如 在我的工作中 我应该使
  • 如何查明CONFIG_FANOTIFY_ACCESS_PERMISSIONS是否启用?

    我想利用fanotify 7 http man7 org linux man pages man7 fanotify 7 html我遇到的问题是在某些内核上CONFIG FANOTIFY ACCESS PERMISSIONS不起作用 虽然C
  • 以编程方式使用自定义元素创建网格

    我正在尝试以编程方式创建一个网格 并将自定义控件作为子项附加到网格中 作为 2x2 矩阵中的第 0 行第 0 列 为了让事情变得更棘手 我使用了 MVVM 设计模式 下面是一些代码可以帮助大家理解这个想法 应用程序 xaml cs base
  • 如何确定母版页中正在显示哪个子页?

    我正在母版页上编写代码 我需要知道正在显示哪个子 内容 页面 我怎样才能以编程方式做到这一点 我用这个 string pageName this ContentPlaceHolder1 Page GetType FullName 它以 AS
  • WPF/数据集:如何通过 XAML 将相关表中的数据绑定到数据网格列中?

    我正在使用 WPF DataSet 连接到 SQL Server Express XAML 和 C Visual Studio 2013 Express 我从名为 BankNoteBook 的现有 SQL Server Express 数据
  • 如何使用 std::array 模拟 C 数组初始化“int arr[] = { e1, e2, e3, ... }”行为?

    注意 这个问题是关于不必指定元素数量并且仍然允许直接初始化嵌套类型 这个问题 https stackoverflow com questions 6111565 now that we have stdarray what uses are

随机推荐

  • Server MyEclipse Tomcat v8.5 was unable to start within 45 seconds.

    MyEclipse启动Tomcat v8 5遇到问题 解决方法之一 直接在MyEclipse上修改 1 在下图中定位到Servers下 双击 MyEclipse Tomcat v8 5 2 在下图中点红框部分 3 在下图中 默认Start的
  • 参数显著性检验的p值小于显著性水平不等于其具有经济学意义

    在做简单线性回归或者多元线性回归时 如何评估参数的统计意义和经济意义是我们研究问题的两个重要方面 理论意义和经济意义是如何显示在数字上的呢 以下是笔者在做相关或者线性回归课题时学习整理出来的 在此分享记录 参数的t统计量足够大 或者p值足够
  • python 接口自动化测试-----常见面试题汇总

    1 软件接口是什么 程序不同模块之间传输数据并作处理的类或函数 2 HTTP 和 HTTPS 协议区别 答 https 协议需要到 CA Certificate Authority 证书颁发机构 申请证书 一般免费证书 较少 因而需要一定费
  • 【Anaconda】基本操作

    1 创建 使用命令查看当前拥有的虚拟环境 conda info envs 在指定目录下创建新的虚拟环境 其中C ProgramData Anaconda3 envs 是创建的目录所在位置 pytorch 是新环境名称 python 3 8是
  • SpringBoot之【mybatisplus】分页插件、条件查询、sql打印开启

    文章目录 一 概述 二 流程 1 sql打印开启 2 分页插件 3 常用条件 一 概述 本篇主要写开启 sql的打印 分页插件开启 条件查询 二 流程 1 sql打印开启 yml文件添加如下配置 mybatis plus 配置slq打印日志
  • ForeFront Chat 免费版GPT-4来了!

    Forefront Chat简介 近日 Forefront AI 正式推出 Forefront Chat 允许用户免费体验GPT 4 的强大功能 Forefront AI 在 Twitter 上表示 今天 我们发布了 Forefront C
  • 为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数?

    本博客可能随时删除或隐藏 请关注微信公众号 获取永久内容 微信搜索 编程笔记本 获取更多信息 codingbook2020 今天我们来谈一谈面试 C 工程师时经常被谈到的一个问题 为什么析构函数必须是虚函数 为什么默认的析构函数不是虚函数
  • java高频面试题(2023最新)

    目录 一 java基础 1 八大基础类型 2 java三大特性 3 重载和重写的区别 4 pubilc protected dafault 不写 private修饰符的作用范围 5 和equals的区别 6 hashcode 值相同 equ
  • 如何解决“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?

    今天在用uniapp框架写小程序 遇到报错 错误原因 微信开发者工具从 1 05 2201210 版本开始 对小程序项目新增了无依赖文件过滤能力 如果某个 js 文件被静态分析显示是无依赖文件 在实际运行时又被其他 js 文件 requir
  • java 文件读取和写入

    1 文件名 1 InputStream 字节流 和Reader 字符流 2 OutputStream 字节流 和 Writer 字符流 1 文件名 Java提供了File类 来表示一个文件 通过构造方法来指定路径 绝对路径 目录与目录之间用
  • BUCK电路-TL494方案 持续更新大概2周更新完成

    目录 一 电磁感应现象 这个现象是如何产生的 磁生电的变换的条件 二 电感的伏安特性 计算磁场大小可以用上面这个公式 磁感应强度B来表示 u0是真空磁导率 N是线圈的匝数 I是通过这个线圈的的电流大小 电生磁的过程就是由I来生成这个B 可以
  • SpringBoot 整合 ChatGPT API 项目实战,挣了3K!

    大家好 我是老赵 体验到了ChatGPT的强大之后 那么我们会想 如果我们想基于ChatGPT开发一个自己的聊天机器人 这个能搞定吗 ChatGPT平台已经为技术提供了一个入口了 很简单的就是实现了 一 准备工作 1 已成功注册 OpenA
  • Jmeter多接口测试之参数传递

    接口测试包含单接口测试和多接口测试 通过组合多个接口实现一组功能的验证称为多接口测试 单接口重在单个接口多种请求组合的响应断言 多接口重在组合不同接口 实现流程的串联和验证 多接口测试涉及到接口之间参数的传递 比如AB两个接口协同完成一个功
  • DDOS高防ip是什么?有什么用?

    ddos高防ip是网络安全公司针对服务器在遭受大流量的ddos攻击导致服务不可用的情况 推出的付费增值服务 ddos攻击是通过用大量的无效流量数据对该IP的服务器进行请求 导致服务器的资源被大量占用 无法对正确的请求作出响应通过配置ddos
  • shell变量的设定规则

    内容摘自鸟哥的Linux 私房菜 1 变量与变量内容以一个等号 来连结 如下所示 myname VBird 2 等号两边不能直接接空格符 如下所示为错误 myname VBird 或 myname VBird Tsai 3 变量名称只能是英
  • Django基础之Admin后台数据管理

    Admin后台数据管理 一个站点或者网站 除了给用户浏览及操作外 还需要对后台数据进行管理 比如添加商品 修改商品等等 Django提供了一个可插拔的后台管理系统 Admin 应用 该系统可以从模型中读取元数据 并提供以模型为中心的界面 A
  • C语言文件通讯录制作说明

    文件通讯 前言 很多计算机专业大学生第一个课设就是校园出入管理系统或者文件版通讯录 这些软件工程不仅可以锻炼我们的编程能力 也可以让我们更为深刻的理解C语言知识 为将来的学习打下基础 但是同学们肯定会有所疑问 下面是我的一个范例 提示 以下
  • 高德地图 – 1.问题集锦

    1 自动加载文本框的坐标 并在地图标注点 2 点击地图时 并且 逆地理编码 解析出地址方在文本框 js var lnglatXY var marker 初始化地图对象 加载地图 var map new AMap Map mapContain
  • 【PB】动态添加数据窗口列中下拉列表的内容

    1 设置数据窗口某个列 dept id 的style type为DropDownListBox dw 1 Modify dept id ddlb case any 2 为下拉列表框添加数据 boolean lb flag false str
  • 剖析C++标准库智能指针(std::auto_ptr)

    1 Do you Smart Pointer Smart Pointer 中文名 智能指针 舶来品 不可否认 资源泄露 resource leak 曾经是C 程序的一大噩梦 垃圾回收 机制 Garbage Collection 一时颇受注目