2010-12-13 6 views
5

मैं std :: shared_ptr का एक सुरक्षित संस्करण लागू करने की कोशिश कर रहा हूं, जिसे "safe_ptr" कहा जाता है जो "गैर-शून्यता" की गारंटी देता है।safe_ptr कार्यान्वयन

संपादित करें: हटाया गया प्रश्न। रुचि रखते हैं तो संपादन देखें। रुचि रखने वाले किसी भी व्यक्ति को अंतिम समाधान पोस्ट करना:

यह कोड अब google code पर होस्ट किया गया है।

#pragma once 

#include <memory> 
#include <type_traits> 
#include <exception> 

template<typename T> 
class safe_ptr 
{ 
    template <typename> friend class safe_ptr; 
public: 
    typedef T element_type; 

    safe_ptr() : impl_(std::make_shared<T>()){} 

    safe_ptr(const safe_ptr<T>& other) : impl_(other.impl_){} 

    template<typename U> 
    safe_ptr(const safe_ptr<U>& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(other.impl_){} 

    template<typename U>  
    safe_ptr(const U& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0) 
     : impl_(std::make_shared<U>(impl)) {} 

    template<typename U, typename D>   
    safe_ptr(const U& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0) 
     : impl_(new U(impl), dtor) {} 

    template<typename U>  
    safe_ptr(U&& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0) 
     : impl_(std::make_shared<U>(std::forward<U>(impl))) {} 

    template<typename U, typename D>  
    safe_ptr(U&& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0) 
     : impl_(new U(std::forward<U>(impl)), dtor) {} 

    template<typename U>  
    explicit safe_ptr(const std::shared_ptr<U>& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl) 
    { 
     if(!impl_) 
      throw std::invalid_argument("impl"); 
    } 

    template<typename U>  
    explicit safe_ptr(std::shared_ptr<U>&& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(std::move(impl)) 
    { 
     if(!impl_) 
      throw std::invalid_argument("impl"); 
    } 

    template<typename U>  
    explicit safe_ptr(U* impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl) 
    { 
     if(!impl_) 
      throw std::invalid_argument("impl"); 
    } 

    template<typename U, typename D>  
    explicit safe_ptr(U* impl, D dtor, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl, dtor) 
    { 
     if(!impl_) 
      throw std::invalid_argument("impl"); 
    } 

    template<typename U> 
    typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr<T>&>::type 
    operator=(const safe_ptr<U>& other) 
    { 
     safe_ptr<T> temp(other); 
     temp.swap(*this); 
     return *this; 
    } 

    template <typename U> 
    typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, safe_ptr<T>&>::type 
    operator=(U&& impl) 
    { 
     safe_ptr<T> temp(std::forward<T>(impl)); 
     temp.swap(*this); 
     return *this; 
    } 

    T& operator*() const { return *impl_.get();} 

    T* operator->() const { return impl_.get();} 

    T* get() const { return impl_.get();} 

    bool unique() const { return impl_.unique();} 

    long use_count() const { return impl_.use_count();} 

    void swap(safe_ptr& other) { impl_.swap(other.impl_); } 

    operator std::shared_ptr<T>() const { return impl_;} 

    template<class U> 
    bool owner_before(const safe_ptr<T>& ptr){ return impl_.owner_before(ptr.impl_); } 

    template<class U> 
    bool owner_before(const std::shared_ptr<U>& ptr){ return impl_.owner_before(ptr); } 

    template<class D, class U> 
    D* get_deleter(safe_ptr<U> const& ptr) { return impl_.get_deleter(); } 

private:  
    std::shared_ptr<T> impl_; 
}; 

template<class T, class U> 
bool operator==(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() == b.get(); 
} 

template<class T, class U> 
bool operator!=(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() != b.get(); 
} 

template<class T, class U> 
bool operator<(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() < b.get(); 
} 

template<class T, class U> 
bool operator>(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() > b.get(); 
} 

template<class T, class U> 
bool operator>=(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() >= b.get(); 
} 

template<class T, class U> 
bool operator<=(const safe_ptr<T>& a, const safe_ptr<U>& b) 
{ 
    return a.get() <= b.get(); 
} 

template<class E, class T, class U> 
std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out, const safe_ptr<U>& p) 
{ 
    return out << p.get(); 
} 

template<class T> 
void swap(safe_ptr<T>& a, safe_ptr<T>& b) 
{ 
    a.swap(b); 
} 

template<class T> 
T* get_pointer(safe_ptr<T> const& p) 
{ 
    return p.get(); 
} 

template <class T, class U> 
safe_ptr<T> static_pointer_cast(const safe_ptr<U>& p) 
{ 
    return safe_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(p))); 
} 

template <class T, class U> 
safe_ptr<T> const_pointer_cast(const safe_ptr<U>& p) 
{ 
    return safe_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(p))); 
} 

template <class T, class U> 
safe_ptr<T> dynamic_pointer_cast(const safe_ptr<U>& p) 
{ 
    auto temp = std::dynamic_pointer_cast<T>(std::shared_ptr<U>(p)); 
    if(!temp) 
     throw std::bad_cast(); 
    return safe_ptr<T>(temp); 
} 

template<typename T> 
safe_ptr<T> make_safe() 
{ 
    return safe_ptr<T>(); 
} 

template<typename T, typename P0> 
safe_ptr<T> make_safe(P0&& p0) 
{ 
    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0))); 
} 

template<typename T, typename P0, typename P1> 
safe_ptr<T> make_safe(P0&& p0, P1&& p1) 
{ 
    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1))); 
} 

template<typename T, typename P0, typename P1, typename P2> 
safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2) 
{ 
    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2))); 
} 

template<typename T, typename P0, typename P1, typename P2, typename P3> 
safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3) 
{ 
    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3))); 
} 

template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4> 
safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&&) 
{ 
    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P3>(p4))); 
} 
+1

+1 अच्छा काम करते हैं। आप इसे किसी भी प्रकार के लाइसेंस के तहत जारी कर रहे हैं? – KitsuneYMG

+0

मुझे लगता है कि यह जीएनयू जनरल पब्लिक लाइसेंस 3 या उच्चतम के तहत होगा। यदि आप किसी प्रोजेक्ट में इसका इस्तेमाल करते हैं तो मैं मेल की भी सराहना करता हूं। – ronag

+0

मेल: [email protected] – ronag

उत्तर

4

आपको is_convertible पर तर्क मिला है। आप जाँच करना चाहते हैं T* को Y* जो के रूप में व्यक्त किया जाता है:

std::is_convertible<Y*, T*> 

अपने संपादित के बारे में: हां, तो आप एक दोस्त घोषणा

// Within the body of the class 
template <typename> friend class safe_ptr; // the syntax is peculiar... 

इसके अलावा जरूरत है, तो आप safe_ptr के लिए एक डिफ़ॉल्ट निर्माता भी प्रदान कर सकता है, जो स्वाभाविक रूप से डिफ़ॉल्ट वस्तु का निर्माण करता है। मैं आपके पिछले प्रश्न के उत्तर में दिए गए ऑब्जेक्ट के डिफ़ॉल्ट कन्स्ट्रक्टर का आविष्कार करने के बारे में भूल गया था :)

1

मुझे लगता है कि आप is_convertible बैकवार्क का उपयोग कर रहे हैं।

template<typename Y> 
safe_ptr(const safe_ptr<Y>& other, typename std::enable_if<std::is_convertible<Y*, T*>::value, void*>::type = 0) : impl_(other.impl_){} 
+0

अच्छा पकड़ ... हालांकि अब मुझे एक नई समस्या है ... कृपया संपादन देखें। – ronag

+0

@ronag: हाँ, यह एक सुलभता समस्या है, जिसे एक मित्र घोषणा का समाधान होगा। मैथ्यूयू ने अपने जवाब में एक उदाहरण दिया। –

1

निजी सदस्य impl_ की पहुंच के लिए, आपको safe_ptr टेम्पलेट के विभिन्न तत्कालताओं से मित्रतापूर्ण होना चाहिए।

template <class Y> friend class safe_ptr;