SmartPtr.h

   1 ////////////////////////////////////////////////////////////////////////////////
   2 // The Loki Library
   3 // Copyright (c) 2001 by Andrei Alexandrescu
   4 // This code accompanies the book:
   5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
   6 //     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
   7 // Permission to use, copy, modify, distribute and sell this software for any 
   8 //     purpose is hereby granted without fee, provided that the above copyright 
   9 //     notice appear in all copies and that both that copyright notice and this 
  10 //     permission notice appear in supporting documentation.
  11 // The author or Addison-Welsey Longman make no representations about the 
  12 //     suitability of this software for any purpose. It is provided "as is" 
  13 //     without express or implied warranty.
  14 ////////////////////////////////////////////////////////////////////////////////
  15 
  16 // Last update: June 20, 2001
  17 
  18 #ifndef SMARTPTR_INC_
  19 #define SMARTPTR_INC_
  20 
  21 ////////////////////////////////////////////////////////////////////////////////
  22 // IMPORTANT NOTE
  23 // Due to threading issues, the OwnershipPolicy has been changed as follows:
  24 //     Release() returns a boolean saying if that was the last release
  25 //        so the pointer can be deleted by the StoragePolicy
  26 //     IsUnique() was removed
  27 ////////////////////////////////////////////////////////////////////////////////
  28 
  29 
  30 #include "SmallObj.h"
  31 #include "TypeManip.h"
  32 #include "static_check.h"
  33 #include <functional>
  34 #include <stdexcept>
  35 
  36 namespace Loki
  37 {
  38 
  39 ////////////////////////////////////////////////////////////////////////////////
  40 // class template DefaultSPStorage
  41 // Implementation of the StoragePolicy used by SmartPtr
  42 ////////////////////////////////////////////////////////////////////////////////
  43 
  44     template <class T>
  45     class DefaultSPStorage
  46     {
  47     protected:
  48         typedef T* StoredType;    // the type of the pointee_ object
  49         typedef T* PointerType;   // type returned by operator->
  50         typedef T& ReferenceType; // type returned by operator*
  51         
  52     public:
  53         DefaultSPStorage() : pointee_(Default()) 
  54         {}
  55 
  56         // The storage policy doesn't initialize the stored pointer 
  57         //     which will be initialized by the OwnershipPolicy's Clone fn
  58         DefaultSPStorage(const DefaultSPStorage&)
  59         {}
  60 
  61         template <class U>
  62         DefaultSPStorage(const DefaultSPStorage<U>&) 
  63         {}
  64         
  65         DefaultSPStorage(const StoredType& p) : pointee_(p) {}
  66         
  67         PointerType operator->() const { return pointee_; }
  68         
  69         ReferenceType operator*() const { return *pointee_; }
  70         
  71         void Swap(DefaultSPStorage& rhs)
  72         { std::swap(pointee_, rhs.pointee_); }
  73     
  74         // Accessors
  75         friend inline PointerType GetImpl(const DefaultSPStorage& sp)
  76         { return sp.pointee_; }
  77         
  78         friend inline const StoredType& GetImplRef(const DefaultSPStorage& sp)
  79         { return sp.pointee_; }
  80 
  81         friend inline StoredType& GetImplRef(DefaultSPStorage& sp)
  82         { return sp.pointee_; }
  83 
  84     protected:
  85         // Destroys the data stored
  86         // (Destruction might be taken over by the OwnershipPolicy)
  87         void Destroy()
  88         { delete pointee_; }
  89         
  90         // Default value to initialize the pointer
  91         static StoredType Default()
  92         { return 0; }
  93     
  94     private:
  95         // Data
  96         StoredType pointee_;
  97     };
  98 
  99 ////////////////////////////////////////////////////////////////////////////////
 100 // class template RefCounted
 101 // Implementation of the OwnershipPolicy used by SmartPtr
 102 // Provides a classic external reference counting implementation
 103 ////////////////////////////////////////////////////////////////////////////////
 104 
 105     template <class P>
 106     class RefCounted
 107     {
 108     public:
 109         RefCounted() 
 110         {
 111             pCount_ = static_cast<unsigned int*>(
 112                 SmallObject<>::operator new(sizeof(unsigned int)));
 113             assert(pCount_);
 114             *pCount_ = 1;
 115         }
 116         
 117         RefCounted(const RefCounted& rhs) 
 118         : pCount_(rhs.pCount_)
 119         {}
 120         
 121         // MWCW lacks template friends, hence the following kludge
 122         template <typename P1>
 123         RefCounted(const RefCounted<P1>& rhs) 
 124         : pCount_(reinterpret_cast<const RefCounted&>(rhs).pCount_)
 125         {}
 126         
 127         P Clone(const P& val)
 128         {
 129             ++*pCount_;
 130             return val;
 131         }
 132         
 133         bool Release(const P&)
 134         {
 135             if (!--*pCount_)
 136             {
 137                 SmallObject<>::operator delete(pCount_, sizeof(unsigned int));
 138                 return true;
 139             }
 140             return false;
 141         }
 142         
 143         void Swap(RefCounted& rhs)
 144         { std::swap(pCount_, rhs.pCount_); }
 145     
 146         enum { destructiveCopy = false };
 147 
 148     private:
 149         // Data
 150         unsigned int* pCount_;
 151     };
 152     
 153 ////////////////////////////////////////////////////////////////////////////////
 154 // class template RefCountedMT
 155 // Implementation of the OwnershipPolicy used by SmartPtr
 156 // Implements external reference counting for multithreaded programs
 157 ////////////////////////////////////////////////////////////////////////////////
 158     template <class P,
 159         template <class> class ThreadingModel>
 160     class RefCountedMT : public ThreadingModel< RefCountedMT<P, ThreadingModel> >
 161     {
 162     public:
 163         RefCountedMT() 
 164         {
 165             pCount_ = static_cast<unsigned int*>(
 166                 SmallObject<ThreadingModel>::operator new(
 167                     sizeof(unsigned int)));
 168             assert(pCount_);
 169             *pCount_ = 1;
 170         }
 171         
 172         RefCountedMT(const RefCountedMT& rhs) 
 173         : pCount_(rhs.pCount_)
 174         {}
 175         
 176         // MWCW lacks template friends, hence the following kludge
 177         template <typename P1>
 178         RefCountedMT(const RefCountedMT<P1, ThreadingModel>& rhs) 
 179         : pCount_(reinterpret_cast<const RefCounted<P>&>(rhs).pCount_)
 180         {}
 181         
 182         P Clone(const P& val)
 183         {
 184             ThreadingModel<RefCountedMT>::AtomicIncrement(*pCount_);
 185             return val;
 186         }
 187         
 188         bool Release(const P&)
 189         {
 190             if (!ThreadingModel<RefCountedMT>::AtomicDecrement(*pCount_))
 191             {
 192                 SmallObject<ThreadingModel>::operator delete(pCount_, 
 193                     sizeof(unsigned int));
 194                 return true;
 195             }
 196             return false;
 197         }
 198         
 199         void Swap(RefCountedMT& rhs)
 200         { std::swap(pCount_, rhs.pCount_); }
 201     
 202         enum { destructiveCopy = false };
 203 
 204     private:
 205         // Data
 206         volatile unsigned int* pCount_;
 207     };
 208 
 209 ////////////////////////////////////////////////////////////////////////////////
 210 // class template COMRefCounted
 211 // Implementation of the OwnershipPolicy used by SmartPtr
 212 // Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax
 213 ////////////////////////////////////////////////////////////////////////////////
 214 
 215     template <class P>
 216     class COMRefCounted
 217     {
 218     public:
 219         COMRefCounted()
 220         {}
 221         
 222         template <class U>
 223         COMRefCounted(const COMRefCounted<U>&)
 224         {}
 225         
 226         static P Clone(const P& val)
 227         {
 228             val->AddRef();
 229             return val;
 230         }
 231         
 232         static bool Release(const P& val)
 233         { val->Release(); return false; }
 234         
 235         enum { destructiveCopy = false };
 236         
 237         static void Swap(COMRefCounted&)
 238         {}
 239     };
 240 
 241 ////////////////////////////////////////////////////////////////////////////////
 242 // class template DeepCopy
 243 // Implementation of the OwnershipPolicy used by SmartPtr
 244 // Implements deep copy semantics, assumes existence of a Clone() member 
 245 //     function of the pointee type
 246 ////////////////////////////////////////////////////////////////////////////////
 247 
 248     template <class P>
 249     struct DeepCopy
 250     {
 251         DeepCopy()
 252         {}
 253         
 254         template <class P1>
 255         DeepCopy(const DeepCopy<P1>&)
 256         {}
 257         
 258         static P Clone(const P& val)
 259         { return val->Clone(); }
 260         
 261         static bool Release(const P& val)
 262         { return true; }
 263         
 264         static void Swap(DeepCopy&)
 265         {}
 266         
 267         enum { destructiveCopy = false };
 268     };
 269     
 270 ////////////////////////////////////////////////////////////////////////////////
 271 // class template RefLinked
 272 // Implementation of the OwnershipPolicy used by SmartPtr
 273 // Implements reference linking
 274 ////////////////////////////////////////////////////////////////////////////////
 275 
 276     namespace Private
 277     {
 278         class RefLinkedBase
 279         {
 280         public:
 281             RefLinkedBase() 
 282             { prev_ = next_ = this; }
 283             
 284             RefLinkedBase(const RefLinkedBase& rhs) 
 285             {
 286                 prev_ = &rhs;
 287                 next_ = rhs.next_;
 288                 prev_->next_ = this;
 289                 next_->prev_ = this;
 290             }
 291             
 292             bool Release()
 293             {
 294                 if (next_ == this)
 295                 {   
 296                     assert(prev_ == this);
 297                     return true;
 298                 }
 299                 prev_->next_ = next_;
 300                 next_->prev_ = prev_;
 301                 return false;
 302             }
 303             
 304             void Swap(RefLinkedBase& rhs)
 305             {
 306                 if (next_ == this)
 307                 {
 308                     assert(prev_ == this);
 309                     if (rhs.next_ == &rhs)
 310                     {
 311                         assert(rhs.prev_ == &rhs);
 312                         // both lists are empty, nothing 2 do
 313                         return;
 314                     }
 315                     prev_ = rhs.prev_;
 316                     next_ = rhs.next_;
 317                     prev_->next_ = next_->prev_ = this;
 318                     rhs.next_ = rhs.prev_ = &rhs;
 319                     return;
 320                 }
 321                 if (rhs.next_ == &rhs)
 322                 {
 323                     rhs.Swap(*this);
 324                     return;
 325                 }
 326                 std::swap(prev_, rhs.prev_);
 327                 std::swap(next_, rhs.next_);
 328                 std::swap(prev_->next_, rhs.prev_->next_);
 329                 std::swap(next_->prev_, rhs.next_->prev_);
 330             }
 331                 
 332             enum { destructiveCopy = false };
 333 
 334         private:
 335             mutable const RefLinkedBase* prev_;
 336             mutable const RefLinkedBase* next_;
 337         };
 338     }
 339     
 340     template <class P>
 341     class RefLinked : public Private::RefLinkedBase
 342     {
 343     public:
 344         RefLinked()
 345         {}
 346         
 347         template <class P1>
 348         RefLinked(const RefLinked<P1>& rhs) 
 349         : Private::RefLinkedBase(rhs)
 350         {}
 351 
 352         static P Clone(const P& val)
 353         { return val; }
 354 
 355         bool Release(const P&)
 356         { return Private::RefLinkedBase::Release(); }
 357     };
 358     
 359 ////////////////////////////////////////////////////////////////////////////////
 360 // class template DestructiveCopy
 361 // Implementation of the OwnershipPolicy used by SmartPtr
 362 // Implements destructive copy semantics (a la std::auto_ptr)
 363 ////////////////////////////////////////////////////////////////////////////////
 364 
 365     template <class P>
 366     class DestructiveCopy
 367     {
 368     public:
 369         DestructiveCopy()
 370         {}
 371         
 372         template <class P1>
 373         DestructiveCopy(const DestructiveCopy<P1>&)
 374         {}
 375         
 376         template <class P1>
 377         static P Clone(P1& val)
 378         {
 379             P result(val);
 380             val = P1();
 381             return result;
 382         }
 383         
 384         static bool Release(const P&)
 385         { return true; }
 386         
 387         static void Swap(DestructiveCopy&)
 388         {}
 389         
 390         enum { destructiveCopy = true };
 391     };
 392     
 393 ////////////////////////////////////////////////////////////////////////////////
 394 // class template NoCopy
 395 // Implementation of the OwnershipPolicy used by SmartPtr
 396 // Implements a policy that doesn't allow copying objects
 397 ////////////////////////////////////////////////////////////////////////////////
 398 
 399     template <class P>
 400     class NoCopy
 401     {
 402     public:
 403         NoCopy()
 404         {}
 405         
 406         template <class P1>
 407         NoCopy(const NoCopy<P1>&)
 408         {}
 409         
 410         static P Clone(const P&)
 411         {
 412             CT_ASSERT(false, This_Policy_Disallows_Value_Copying);
 413         }
 414         
 415         static bool Release(const P&)
 416         { return true; }
 417         
 418         static void Swap(NoCopy&)
 419         {}
 420         
 421         enum { destructiveCopy = false };
 422     };
 423     
 424 ////////////////////////////////////////////////////////////////////////////////
 425 // class template AllowConversion
 426 // Implementation of the ConversionPolicy used by SmartPtr
 427 // Allows implicit conversion from SmartPtr to the pointee type
 428 ////////////////////////////////////////////////////////////////////////////////
 429 
 430     struct AllowConversion
 431     {
 432         enum { allow = true };
 433 
 434         void Swap(AllowConversion&)
 435         {}
 436     };
 437 
 438 ////////////////////////////////////////////////////////////////////////////////
 439 // class template DisallowConversion
 440 // Implementation of the ConversionPolicy used by SmartPtr
 441 // Does not allow implicit conversion from SmartPtr to the pointee type
 442 // You can initialize a DisallowConversion with an AllowConversion
 443 ////////////////////////////////////////////////////////////////////////////////
 444 
 445     struct DisallowConversion
 446     {
 447         DisallowConversion()
 448         {}
 449         
 450         DisallowConversion(const AllowConversion&)
 451         {}
 452         
 453         enum { allow = false };
 454 
 455         void Swap(DisallowConversion&)
 456         {}
 457     };
 458 
 459 ////////////////////////////////////////////////////////////////////////////////
 460 // class template NoCheck
 461 // Implementation of the CheckingPolicy used by SmartPtr
 462 // Well, it's clear what it does :o)
 463 ////////////////////////////////////////////////////////////////////////////////
 464 
 465     template <class P>
 466     struct NoCheck
 467     {
 468         NoCheck()
 469         {}
 470         
 471         template <class P1>
 472         NoCheck(const NoCheck<P1>&)
 473         {}
 474         
 475         static void OnDefault(const P&)
 476         {}
 477 
 478         static void OnInit(const P&)
 479         {}
 480 
 481         static void OnDereference(const P&)
 482         {}
 483 
 484         static void Swap(NoCheck&)
 485         {}
 486     };
 487 
 488 
 489 ////////////////////////////////////////////////////////////////////////////////
 490 // class template AssertCheck
 491 // Implementation of the CheckingPolicy used by SmartPtr
 492 // Checks the pointer before dereference
 493 ////////////////////////////////////////////////////////////////////////////////
 494 
 495     template <class P>
 496     struct AssertCheck
 497     {
 498         AssertCheck()
 499         {}
 500         
 501         template <class P1>
 502         AssertCheck(const AssertCheck<P1>&)
 503         {}
 504         
 505         template <class P1>
 506         AssertCheck(const NoCheck<P1>&)
 507         {}
 508         
 509         static void OnDefault(const P&)
 510         {}
 511 
 512         static void OnInit(const P&)
 513         {}
 514 
 515         static void OnDereference(P val)
 516         { assert(val); }
 517 
 518         static void Swap(AssertCheck&)
 519         {}
 520     };
 521 
 522 ////////////////////////////////////////////////////////////////////////////////
 523 // class template AssertCheckStrict
 524 // Implementation of the CheckingPolicy used by SmartPtr
 525 // Checks the pointer against zero upon initialization and before dereference
 526 // You can initialize an AssertCheckStrict with an AssertCheck 
 527 ////////////////////////////////////////////////////////////////////////////////
 528 
 529     template <class P>
 530     struct AssertCheckStrict
 531     {
 532         AssertCheckStrict()
 533         {}
 534         
 535         template <class U>
 536         AssertCheckStrict(const AssertCheckStrict<U>&)
 537         {}
 538         
 539         template <class U>
 540         AssertCheckStrict(const AssertCheck<U>&)
 541         {}
 542         
 543         template <class P1>
 544         AssertCheckStrict(const NoCheck<P1>&)
 545         {}
 546         
 547         static void OnDefault(P val)
 548         { assert(val); }
 549         
 550         static void OnInit(P val)
 551         { assert(val); }
 552         
 553         static void OnDereference(P val)
 554         { assert(val); }
 555         
 556         static void Swap(AssertCheckStrict&)
 557         {}
 558     };
 559 
 560 ////////////////////////////////////////////////////////////////////////////////
 561 // class NullPointerException
 562 // Used by some implementations of the CheckingPolicy used by SmartPtr
 563 ////////////////////////////////////////////////////////////////////////////////
 564 
 565     struct NullPointerException : public std::runtime_error
 566     {
 567         NullPointerException() : std::runtime_error("")
 568         { }
 569         const char* what() const
 570         { return "Null Pointer Exception"; }
 571     };
 572         
 573 ////////////////////////////////////////////////////////////////////////////////
 574 // class template RejectNullStatic
 575 // Implementation of the CheckingPolicy used by SmartPtr
 576 // Checks the pointer upon initialization and before dereference
 577 ////////////////////////////////////////////////////////////////////////////////
 578 
 579     template <class P>
 580     struct RejectNullStatic
 581     {
 582         RejectNullStatic()
 583         {}
 584         
 585         template <class P1>
 586         RejectNullStatic(const RejectNullStatic<P1>&)
 587         {}
 588         
 589         template <class P1>
 590         RejectNullStatic(const NoCheck<P1>&)
 591         {}
 592         
 593         template <class P1>
 594         RejectNullStatic(const AssertCheck<P1>&)
 595         {}
 596         
 597         template <class P1>
 598         RejectNullStatic(const AssertCheckStrict<P1>&)
 599         {}
 600         
 601         static void OnDefault(const P&)
 602         {
 603             CompileTimeError<false>
 604                 ERROR_This_Policy_Does_Not_Allow_Default_Initialization;
 605         }
 606         
 607         static void OnInit(const P& val)
 608         { if (!val) throw NullPointerException(); }
 609         
 610         static void OnDereference(const P& val)
 611         { if (!val) throw NullPointerException(); }
 612         
 613         static void Swap(RejectNullStatic&)
 614         {}
 615     };
 616 
 617 ////////////////////////////////////////////////////////////////////////////////
 618 // class template RejectNull
 619 // Implementation of the CheckingPolicy used by SmartPtr
 620 // Checks the pointer before dereference
 621 ////////////////////////////////////////////////////////////////////////////////
 622 
 623     template <class P>
 624     struct RejectNull
 625     {
 626         RejectNull()
 627         {}
 628         
 629         template <class P1>
 630         RejectNull(const RejectNull<P1>&)
 631         {}
 632         
 633         static void OnInit(P val)
 634         { if (!val) throw NullPointerException(); }
 635 
 636         static void OnDefault(P val)
 637         { OnInit(val); }
 638         
 639         void OnDereference(P val)
 640         { OnInit(val); }
 641         
 642         void Swap(RejectNull&)
 643         {}        
 644     };
 645 
 646 ////////////////////////////////////////////////////////////////////////////////
 647 // class template RejectNullStrict
 648 // Implementation of the CheckingPolicy used by SmartPtr
 649 // Checks the pointer upon initialization and before dereference
 650 ////////////////////////////////////////////////////////////////////////////////
 651 
 652     template <class P>
 653     struct RejectNullStrict
 654     {
 655         RejectNullStrict()
 656         {}
 657         
 658         template <class P1>
 659         RejectNullStrict(const RejectNullStrict<P1>&)
 660         {}
 661         
 662         template <class P1>
 663         RejectNullStrict(const RejectNull<P1>&)
 664         {}
 665         
 666         static void OnInit(P val)
 667         { if (!val) throw NullPointerException(); }
 668 
 669         void OnDereference(P val)
 670         { OnInit(val); }
 671         
 672         void Swap(RejectNullStrict&)
 673         {}        
 674     };
 675 
 676 ////////////////////////////////////////////////////////////////////////////////
 677 // class template ByRef
 678 // Transports a reference as a value
 679 // Serves to implement the Colvin/Gibbons trick for SmartPtr
 680 ////////////////////////////////////////////////////////////////////////////////
 681 
 682     template <class T>
 683     class ByRef
 684     {
 685     public:
 686         ByRef(T& v) : value_(v) {}
 687         operator T&() { return value_; }
 688         // gcc doesn't like this:
 689         // operator const T&() const { return value_; }
 690     private:
 691         T& value_;
 692     };
 693 
 694 ////////////////////////////////////////////////////////////////////////////////
 695 // class template SmartPtr (declaration)
 696 // The reason for all the fuss above
 697 ////////////////////////////////////////////////////////////////////////////////
 698 
 699     template
 700     <
 701         typename T,
 702         template <class> class OwnershipPolicy = RefCounted,
 703         class ConversionPolicy = DisallowConversion,
 704         template <class> class CheckingPolicy = AssertCheck,
 705         template <class> class StoragePolicy = DefaultSPStorage
 706     >
 707     class SmartPtr;
 708 
 709 ////////////////////////////////////////////////////////////////////////////////
 710 // class template SmartPtr (definition)
 711 ////////////////////////////////////////////////////////////////////////////////
 712 
 713     template
 714     <
 715         typename T,
 716         template <class> class OwnershipPolicy,
 717         class ConversionPolicy,
 718         template <class> class CheckingPolicy,
 719         template <class> class StoragePolicy
 720     >
 721     class SmartPtr
 722         : public StoragePolicy<T>
 723         , public OwnershipPolicy<typename StoragePolicy<T>::PointerType>
 724         , public CheckingPolicy<typename StoragePolicy<T>::StoredType>
 725         , public ConversionPolicy
 726     {
 727         typedef StoragePolicy<T> SP;
 728         typedef OwnershipPolicy<typename StoragePolicy<T>::PointerType> OP;
 729         typedef CheckingPolicy<typename StoragePolicy<T>::StoredType> KP;
 730         typedef ConversionPolicy CP;
 731         
 732     public:
 733         typedef typename SP::PointerType PointerType;
 734         typedef typename SP::StoredType StoredType;
 735         typedef typename SP::ReferenceType ReferenceType;
 736         
 737         typedef typename Select<OP::destructiveCopy, 
 738                 SmartPtr, const SmartPtr>::Result
 739             CopyArg;
 740     
 741         SmartPtr()
 742         { KP::OnDefault(GetImpl(*this)); }
 743         
 744         SmartPtr(const StoredType& p) : SP(p)
 745         { KP::OnInit(GetImpl(*this)); }
 746         
 747         SmartPtr(CopyArg& rhs)
 748         : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
 749         { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
 750 
 751         template
 752         <
 753             typename T1,
 754             template <class> class OP1,
 755             class CP1,
 756             template <class> class KP1,
 757             template <class> class SP1
 758         >
 759         SmartPtr(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
 760         : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
 761         { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
 762 
 763         template
 764         <
 765             typename T1,
 766             template <class> class OP1,
 767             class CP1,
 768             template <class> class KP1,
 769             template <class> class SP1
 770         >
 771         SmartPtr(SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
 772         : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
 773         { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); }
 774 
 775         SmartPtr(ByRef<SmartPtr> rhs)
 776         : SP(rhs), OP(rhs), KP(rhs), CP(rhs)
 777         {}
 778         
 779         operator ByRef<SmartPtr>()
 780         { return ByRef<SmartPtr>(*this); }
 781 
 782         SmartPtr& operator=(CopyArg& rhs)
 783         {
 784             SmartPtr temp(rhs);
 785             temp.Swap(*this);
 786             return *this;
 787         }
 788 
 789         template
 790         <
 791             typename T1,
 792             template <class> class OP1,
 793             class CP1,
 794             template <class> class KP1,
 795             template <class> class SP1
 796         >
 797         SmartPtr& operator=(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
 798         {
 799             SmartPtr temp(rhs);
 800             temp.Swap(*this);
 801             return *this;
 802         }
 803         
 804         template
 805         <
 806             typename T1,
 807             template <class> class OP1,
 808             class CP1,
 809             template <class> class KP1,
 810             template <class> class SP1
 811         >
 812         SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs)
 813         {
 814             SmartPtr temp(rhs);
 815             temp.Swap(*this);
 816             return *this;
 817         }
 818         
 819         void Swap(SmartPtr& rhs)
 820         {
 821             OP::Swap(rhs);
 822             CP::Swap(rhs);
 823             KP::Swap(rhs);
 824             SP::Swap(rhs);
 825         }
 826         
 827         ~SmartPtr()
 828         {
 829             if (OP::Release(GetImpl(*static_cast<SP*>(this))))
 830             {
 831                 SP::Destroy();
 832             }
 833         }
 834         
 835         friend inline void Release(SmartPtr& sp, typename SP::StoredType& p)
 836         {
 837             p = GetImplRef(sp);
 838             GetImplRef(sp) = SP::Default();
 839         }
 840         
 841         friend inline void Reset(SmartPtr& sp, typename SP::StoredType p)
 842         { SmartPtr(p).Swap(sp); }
 843 
 844         PointerType operator->()
 845         {
 846             KP::OnDereference(GetImplRef(*this));
 847             return SP::operator->();
 848         }
 849 
 850         PointerType operator->() const
 851         {
 852             KP::OnDereference(GetImplRef(*this));
 853             return SP::operator->();
 854         }
 855 
 856         ReferenceType operator*()
 857         {
 858             KP::OnDereference(GetImplRef(*this));
 859             return SP::operator*();
 860         }
 861         
 862         ReferenceType operator*() const
 863         {
 864             KP::OnDereference(GetImplRef(*this));
 865             return SP::operator*();
 866         }
 867         
 868         bool operator!() const // Enables "if (!sp) ..."
 869         { return GetImpl(*this) == 0; }
 870         
 871         inline friend bool operator==(const SmartPtr& lhs,
 872             const T* rhs)
 873         { return GetImpl(lhs) == rhs; }
 874         
 875         inline friend bool operator==(const T* lhs,
 876             const SmartPtr& rhs)
 877         { return rhs == lhs; }
 878         
 879         inline friend bool operator!=(const SmartPtr& lhs,
 880             const T* rhs)
 881         { return !(lhs == rhs); }
 882         
 883         inline friend bool operator!=(const T* lhs,
 884             const SmartPtr& rhs)
 885         { return rhs != lhs; }
 886 
 887         // Ambiguity buster
 888         template
 889         <
 890             typename T1,
 891             template <class> class OP1,
 892             class CP1,
 893             template <class> class KP1,
 894             template <class> class SP1
 895         >
 896         bool operator==(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
 897         { return *this == GetImpl(rhs); }
 898 
 899         // Ambiguity buster
 900         template
 901         <
 902             typename T1,
 903             template <class> class OP1,
 904             class CP1,
 905             template <class> class KP1,
 906             template <class> class SP1
 907         >
 908         bool operator!=(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
 909         { return !(*this == rhs); }
 910 
 911         // Ambiguity buster
 912         template
 913         <
 914             typename T1,
 915             template <class> class OP1,
 916             class CP1,
 917             template <class> class KP1,
 918             template <class> class SP1
 919         >
 920         bool operator<(const SmartPtr<T1, OP1, CP1, KP1, SP1>& rhs) const
 921         { return *this < GetImpl(rhs); }
 922 
 923     private:
 924         // Helper for enabling 'if (sp)'
 925         struct Tester
 926         {
 927             Tester() {}
 928         private:
 929             void operator delete(void*);
 930         };
 931         
 932     public:
 933         // enable 'if (sp)'
 934         operator Tester*() const
 935         {
 936             if (!*this) return 0;
 937             static Tester t;
 938             return &t;
 939         }
 940 
 941     private:
 942         // Helper for disallowing automatic conversion
 943         struct Insipid
 944         {
 945             Insipid(PointerType) {}
 946         };
 947         
 948         typedef typename Select<CP::allow, PointerType, Insipid>::Result
 949             AutomaticConversionResult;
 950     
 951     public:        
 952         operator AutomaticConversionResult() const
 953         { return GetImpl(*this); }
 954     };
 955 
 956 ////////////////////////////////////////////////////////////////////////////////
 957 // free comparison operators for class template SmartPtr
 958 ////////////////////////////////////////////////////////////////////////////////
 959 
 960 ////////////////////////////////////////////////////////////////////////////////
 961 // operator== for lhs = SmartPtr, rhs = raw pointer
 962 ////////////////////////////////////////////////////////////////////////////////
 963 
 964     template
 965     <
 966         typename T,
 967         template <class> class OP,
 968         class CP,
 969         template <class> class KP,
 970         template <class> class SP,
 971         typename U
 972     >
 973     inline bool operator==(const SmartPtr<T, OP, CP, KP, SP>& lhs,
 974         const U* rhs)
 975     { return GetImpl(lhs) == rhs; }
 976     
 977 ////////////////////////////////////////////////////////////////////////////////
 978 // operator== for lhs = raw pointer, rhs = SmartPtr
 979 ////////////////////////////////////////////////////////////////////////////////
 980 
 981     template
 982     <
 983         typename T,
 984         template <class> class OP,
 985         class CP,
 986         template <class> class KP,
 987         template <class> class SP,
 988         typename U
 989     >
 990     inline bool operator==(const U* lhs,
 991         const SmartPtr<T, OP, CP, KP, SP>& rhs)
 992     { return rhs == lhs; }
 993 
 994 ////////////////////////////////////////////////////////////////////////////////
 995 // operator!= for lhs = SmartPtr, rhs = raw pointer
 996 ////////////////////////////////////////////////////////////////////////////////
 997 
 998     template
 999     <
1000         typename T,
1001         template <class> class OP,
1002         class CP,
1003         template <class> class KP,
1004         template <class> class SP,
1005         typename U
1006     >
1007     inline bool operator!=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1008         const U* rhs)
1009     { return !(lhs == rhs); }
1010     
1011 ////////////////////////////////////////////////////////////////////////////////
1012 // operator!= for lhs = raw pointer, rhs = SmartPtr
1013 ////////////////////////////////////////////////////////////////////////////////
1014 
1015     template
1016     <
1017         typename T,
1018         template <class> class OP,
1019         class CP,
1020         template <class> class KP,
1021         template <class> class SP,
1022         typename U
1023     >
1024     inline bool operator!=(const U* lhs,
1025         const SmartPtr<T, OP, CP, KP, SP>& rhs)
1026     { return rhs != lhs; }
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 // operator< for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED
1030 ////////////////////////////////////////////////////////////////////////////////
1031 
1032     template
1033     <
1034         typename T,
1035         template <class> class OP,
1036         class CP,
1037         template <class> class KP,
1038         template <class> class SP,
1039         typename U
1040     >
1041     inline bool operator<(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1042         const U* rhs);
1043         
1044 ////////////////////////////////////////////////////////////////////////////////
1045 // operator< for lhs = raw pointer, rhs = SmartPtr -- NOT DEFINED
1046 ////////////////////////////////////////////////////////////////////////////////
1047 
1048     template
1049     <
1050         typename T,
1051         template <class> class OP,
1052         class CP,
1053         template <class> class KP,
1054         template <class> class SP,
1055         typename U
1056     >
1057     inline bool operator<(const U* lhs,
1058         const SmartPtr<T, OP, CP, KP, SP>& rhs);
1059         
1060 ////////////////////////////////////////////////////////////////////////////////
1061 // operator> for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED
1062 ////////////////////////////////////////////////////////////////////////////////
1063 
1064     template
1065     <
1066         typename T,
1067         template <class> class OP,
1068         class CP,
1069         template <class> class KP,
1070         template <class> class SP,
1071         typename U
1072     >
1073     inline bool operator>(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1074         const U* rhs)
1075     { return rhs < lhs; }
1076         
1077 ////////////////////////////////////////////////////////////////////////////////
1078 // operator> for lhs = raw pointer, rhs = SmartPtr
1079 ////////////////////////////////////////////////////////////////////////////////
1080 
1081     template
1082     <
1083         typename T,
1084         template <class> class OP,
1085         class CP,
1086         template <class> class KP,
1087         template <class> class SP,
1088         typename U
1089     >
1090     inline bool operator>(const U* lhs,
1091         const SmartPtr<T, OP, CP, KP, SP>& rhs)
1092     { return rhs < lhs; }
1093   
1094 ////////////////////////////////////////////////////////////////////////////////
1095 // operator<= for lhs = SmartPtr, rhs = raw pointer
1096 ////////////////////////////////////////////////////////////////////////////////
1097 
1098     template
1099     <
1100         typename T,
1101         template <class> class OP,
1102         class CP,
1103         template <class> class KP,
1104         template <class> class SP,
1105         typename U
1106     >
1107     inline bool operator<=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1108         const U* rhs)
1109     { return !(rhs < lhs); }
1110         
1111 ////////////////////////////////////////////////////////////////////////////////
1112 // operator<= for lhs = raw pointer, rhs = SmartPtr
1113 ////////////////////////////////////////////////////////////////////////////////
1114 
1115     template
1116     <
1117         typename T,
1118         template <class> class OP,
1119         class CP,
1120         template <class> class KP,
1121         template <class> class SP,
1122         typename U
1123     >
1124     inline bool operator<=(const U* lhs,
1125         const SmartPtr<T, OP, CP, KP, SP>& rhs)
1126     { return !(rhs < lhs); }
1127 
1128 ////////////////////////////////////////////////////////////////////////////////
1129 // operator>= for lhs = SmartPtr, rhs = raw pointer
1130 ////////////////////////////////////////////////////////////////////////////////
1131 
1132     template
1133     <
1134         typename T,
1135         template <class> class OP,
1136         class CP,
1137         template <class> class KP,
1138         template <class> class SP,
1139         typename U
1140     >
1141     inline bool operator>=(const SmartPtr<T, OP, CP, KP, SP>& lhs,
1142         const U* rhs)
1143     { return !(lhs < rhs); }
1144         
1145 ////////////////////////////////////////////////////////////////////////////////
1146 // operator>= for lhs = raw pointer, rhs = SmartPtr
1147 ////////////////////////////////////////////////////////////////////////////////
1148 
1149     template
1150     <
1151         typename T,
1152         template <class> class OP,
1153         class CP,
1154         template <class> class KP,
1155         template <class> class SP,
1156         typename U
1157     >
1158     inline bool operator>=(const U* lhs,
1159         const SmartPtr<T, OP, CP, KP, SP>& rhs)
1160     { return !(lhs < rhs); }
1161 
1162 } // namespace Loki
1163 
1164 ////////////////////////////////////////////////////////////////////////////////
1165 // specialization of std::less for SmartPtr
1166 ////////////////////////////////////////////////////////////////////////////////
1167 
1168 namespace std
1169 {
1170     template
1171     <
1172         typename T,
1173         template <class> class OP,
1174         class CP,
1175         template <class> class KP,
1176         template <class> class SP
1177     >
1178     struct less< Loki::SmartPtr<T, OP, CP, KP, SP> >
1179         : public binary_function<Loki::SmartPtr<T, OP, CP, KP, SP>,
1180             Loki::SmartPtr<T, OP, CP, KP, SP>, bool>
1181     {
1182         bool operator()(const Loki::SmartPtr<T, OP, CP, KP, SP>& lhs,
1183             const Loki::SmartPtr<T, OP, CP, KP, SP>& rhs) const
1184         { return less<T*>()(GetImpl(lhs), GetImpl(rhs)); }
1185     };
1186 }
1187 
1188 ////////////////////////////////////////////////////////////////////////////////
1189 // Change log:
1190 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
1191 ////////////////////////////////////////////////////////////////////////////////
1192 
1193 #endif // SMARTPTR_INC_
posted @ 2012-10-31 15:22  crazylhf  阅读(400)  评论(0)    收藏  举报