DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

ScopedPointer.hpp (10776B)


      1 /*
      2  * DISTRHO Plugin Framework (DPF)
      3  * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com>
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
      6  * or without fee is hereby granted, provided that the above copyright notice and this
      7  * permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
     10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
     11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #ifndef DISTRHO_SCOPED_POINTER_HPP_INCLUDED
     18 #define DISTRHO_SCOPED_POINTER_HPP_INCLUDED
     19 
     20 #include "../DistrhoUtils.hpp"
     21 
     22 #include <algorithm>
     23 
     24 START_NAMESPACE_DISTRHO
     25 
     26 // -----------------------------------------------------------------------
     27 // The following code was based from juce-core ScopedPointer class
     28 
     29 /**
     30    Copyright (C) 2013 Raw Material Software Ltd.
     31 
     32    Permission is granted to use this software under the terms of the ISC license
     33    http://www.isc.org/downloads/software-support-policy/isc-license/
     34 
     35    Permission to use, copy, modify, and/or distribute this software for any
     36    purpose with or without fee is hereby granted, provided that the above
     37    copyright notice and this permission notice appear in all copies.
     38 
     39    THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
     40    TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     41    FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
     42    OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
     43    USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     44    TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     45    OF THIS SOFTWARE.
     46 */
     47 
     48 //==============================================================================
     49 /**
     50     This class holds a pointer which is automatically deleted when this object goes
     51     out of scope.
     52 
     53     Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
     54     gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
     55     as member variables is a good way to use RAII to avoid accidentally leaking dynamically
     56     created objects.
     57 
     58     A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
     59     to an object. If you use the assignment operator to assign a different object to a
     60     ScopedPointer, the old one will be automatically deleted.
     61 
     62     A const ScopedPointer is guaranteed not to lose ownership of its object or change the
     63     object to which it points during its lifetime. This means that making a copy of a const
     64     ScopedPointer is impossible, as that would involve the new copy taking ownership from the
     65     old one.
     66 
     67     If you need to get a pointer out of a ScopedPointer without it being deleted, you
     68     can use the release() method.
     69 
     70     Something to note is the main difference between this class and the std::auto_ptr class,
     71     which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr
     72     requires that you always call get() to retrieve the pointer. The advantages of providing
     73     the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much
     74     exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
     75     use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
     76     to return a ScopedPointer as the result of a function. To avoid this causing errors,
     77     ScopedPointer contains an overloaded constructor that should cause a syntax error in these
     78     circumstances, but it does mean that instead of returning a ScopedPointer from a function,
     79     you'd need to return a raw pointer (or use a std::auto_ptr instead).
     80 */
     81 template<class ObjectType>
     82 class ScopedPointer
     83 {
     84 public:
     85     //==============================================================================
     86     /** Creates a ScopedPointer containing a null pointer. */
     87     ScopedPointer() noexcept
     88         : object(nullptr) {}
     89 
     90     /** Creates a ScopedPointer that owns the specified object. */
     91     ScopedPointer(ObjectType* const objectToTakePossessionOf) noexcept
     92         : object(objectToTakePossessionOf) {}
     93 
     94     /** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
     95 
     96         Because a pointer can only belong to one ScopedPointer, this transfers
     97         the pointer from the other object to this one, and the other object is reset to
     98         be a null pointer.
     99     */
    100     ScopedPointer(ScopedPointer& objectToTransferFrom) noexcept
    101         : object(objectToTransferFrom.object)
    102     {
    103         objectToTransferFrom.object = nullptr;
    104     }
    105 
    106     /** Destructor.
    107         This will delete the object that this ScopedPointer currently refers to.
    108     */
    109     ~ScopedPointer()
    110     {
    111         delete object;
    112     }
    113 
    114     /** Changes this ScopedPointer to point to a new object.
    115 
    116         Because a pointer can only belong to one ScopedPointer, this transfers
    117         the pointer from the other object to this one, and the other object is reset to
    118         be a null pointer.
    119 
    120         If this ScopedPointer already points to an object, that object
    121         will first be deleted.
    122     */
    123     ScopedPointer& operator=(ScopedPointer& objectToTransferFrom)
    124     {
    125         if (this != objectToTransferFrom.getAddress())
    126         {
    127             // Two ScopedPointers should never be able to refer to the same object - if
    128             // this happens, you must have done something dodgy!
    129             DISTRHO_SAFE_ASSERT_RETURN(object == nullptr || object != objectToTransferFrom.object, *this);
    130 
    131             ObjectType* const oldObject = object;
    132             object = objectToTransferFrom.object;
    133             objectToTransferFrom.object = nullptr;
    134             delete oldObject;
    135         }
    136 
    137         return *this;
    138     }
    139 
    140     /** Changes this ScopedPointer to point to a new object.
    141 
    142         If this ScopedPointer already points to an object, that object
    143         will first be deleted.
    144 
    145         The pointer that you pass in may be a nullptr.
    146     */
    147     ScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf)
    148     {
    149         if (object != newObjectToTakePossessionOf)
    150         {
    151             ObjectType* const oldObject = object;
    152             object = newObjectToTakePossessionOf;
    153             delete oldObject;
    154         }
    155 
    156         return *this;
    157     }
    158 
    159     //==============================================================================
    160     /** Returns the object that this ScopedPointer refers to. */
    161     operator ObjectType*() const noexcept   { return object; }
    162 
    163     /** Returns the object that this ScopedPointer refers to. */
    164     ObjectType* get() const noexcept        { return object; }
    165 
    166     /** Returns the object that this ScopedPointer refers to. */
    167     ObjectType& getObject() const noexcept  { return *object; }
    168 
    169     /** Returns the object that this ScopedPointer refers to. */
    170     ObjectType& operator*() const noexcept  { return *object; }
    171 
    172     /** Lets you access methods and properties of the object that this ScopedPointer refers to. */
    173     ObjectType* operator->() const noexcept { return object; }
    174 
    175     //==============================================================================
    176     /** Removes the current object from this ScopedPointer without deleting it.
    177         This will return the current object, and set the ScopedPointer to a null pointer.
    178     */
    179     ObjectType* release() noexcept          { ObjectType* const o = object; object = nullptr; return o; }
    180 
    181     //==============================================================================
    182     /** Swaps this object with that of another ScopedPointer.
    183         The two objects simply exchange their pointers.
    184     */
    185     void swapWith(ScopedPointer<ObjectType>& other) noexcept
    186     {
    187         // Two ScopedPointers should never be able to refer to the same object - if
    188         // this happens, you must have done something dodgy!
    189         DISTRHO_SAFE_ASSERT_RETURN(object != other.object || this == other.getAddress() || object == nullptr,);
    190 
    191         std::swap(object, other.object);
    192     }
    193 
    194 private:
    195     //==============================================================================
    196     ObjectType* object;
    197 
    198     // (Required as an alternative to the overloaded & operator).
    199     const ScopedPointer* getAddress() const noexcept { return this; }
    200 
    201 #ifndef _MSC_VER  // (MSVC can't deal with multiple copy constructors)
    202     /* The copy constructors are private to stop people accidentally copying a const ScopedPointer
    203        (the compiler would let you do so by implicitly casting the source to its raw object pointer).
    204 
    205        A side effect of this is that in a compiler that doesn't support C++11, you may hit an
    206        error when you write something like this:
    207 
    208           ScopedPointer<MyClass> m = new MyClass();  // Compile error: copy constructor is private.
    209 
    210        Even though the compiler would normally ignore the assignment here, it can't do so when the
    211        copy constructor is private. It's very easy to fix though - just write it like this:
    212 
    213           ScopedPointer<MyClass> m (new MyClass());  // Compiles OK
    214 
    215        It's probably best to use the latter form when writing your object declarations anyway, as
    216        this is a better representation of the code that you actually want the compiler to produce.
    217     */
    218 # ifdef DISTRHO_PROPER_CPP11_SUPPORT
    219     ScopedPointer(const ScopedPointer&) = delete;
    220     ScopedPointer& operator=(const ScopedPointer&) = delete;
    221 # else
    222     ScopedPointer(const ScopedPointer&);
    223     ScopedPointer& operator=(const ScopedPointer&);
    224 # endif
    225 #endif
    226 };
    227 
    228 //==============================================================================
    229 /** Compares a ScopedPointer with another pointer.
    230     This can be handy for checking whether this is a null pointer.
    231 */
    232 template<class ObjectType>
    233 bool operator==(const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
    234 {
    235     return static_cast<ObjectType*>(pointer1) == pointer2;
    236 }
    237 
    238 /** Compares a ScopedPointer with another pointer.
    239     This can be handy for checking whether this is a null pointer.
    240 */
    241 template<class ObjectType>
    242 bool operator!=(const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
    243 {
    244     return static_cast<ObjectType*>(pointer1) != pointer2;
    245 }
    246 
    247 // -----------------------------------------------------------------------
    248 
    249 END_NAMESPACE_DISTRHO
    250 
    251 #endif // DISTRHO_SCOPED_POINTER_HPP_INCLUDED