繁体   English   中英

如何避免使用shared_ptr晃晃指针?

[英]How to avoid dangling pointer with shared_ptr?

我有一个类,其对象指针将作为键/数据添加到多个std :: map / std :: unordered_map / hash(内部实现)中。 为了自动删除对象,我正在使用shared_ptr。

我已经设计了使用shared_ptr only类的类。

现在,我要确保将来没有人这样做:

#include <memory>
#include <string>

class A {
 protected:
   struct this_is_private;

 public:
   explicit A(const this_is_private &) {}
   A(const this_is_private &, ::std::string, int) {}

   template <typename... T>
   static ::std::shared_ptr<A> create(T &&...args) {
      return ::std::make_shared<A>(this_is_private{0},
                                   ::std::forward<T>(args)...);
   }

 protected:
   struct this_is_private {
       explicit this_is_private(int) {}
   };

   A(const A &) = delete;
   const A &operator =(const A &) = delete;
};


::std::map<A*, int> m_error;
::std::map<::std::shared_ptr<A>, int> m_ok;

::std::shared_ptr<A> foo()
{
   ::std::shared_ptr<A> temp = A::create();

   A * obj_ptr = temp.get(); 
   m_error.insert(pair<A*, int>(obj_ptr, 10)); //How to make sure no one do this in future
   m_ok.insert(pair<::std::shared_ptr<A>, int>(temp,10)); //ok
}

如何避免使用shared_ptr晃晃指针?

通过根本不存储指向对象的裸指针(也无引用或迭代器),或确保此类指针的生存期短于共享指针的生存期。 后者的正确性不如前者的正确性容易证明。

如何确保将来没有人[存储裸露的指针]

除了完全封装对对象的访问权限之外,C ++语言中没有其他功能可以阻止获取对象的地址并将其存储。 程序员总是有责任承担地址,以确保生存期是-并且将来将是-他们期望的。 更改对象的生存期是程序员的责任,以确保任何内容都不取决于更改的生存期。

有些编程语言已被设计为不允许程序员直接访问对象的地址,从而使此类错误成为不可能。 C ++不是这些语言之一。

将您的shared_ptr隐藏在包装类“ HiddenSharedPointer”中,因此您的类的用户无法直接访问该对象。

#include <memory>
#include <list>
#include <utility>

class A 
{
public:
    class HiddenSharedPointer : private std::shared_ptr<A>
    {
    public:
        template<typename... Args>
        explicit HiddenSharedPointer(Args&&... args);
        HiddenSharedPointer(HiddenSharedPointer&) = default;
        HiddenSharedPointer(const HiddenSharedPointer&) = default;
        HiddenSharedPointer(HiddenSharedPointer&&) = default;
        HiddenSharedPointer& operator=(const HiddenSharedPointer&) = default;
        HiddenSharedPointer& operator=(HiddenSharedPointer&&) = default;

        // methods directly called on the underlying shared_ptr
        using std::shared_ptr<A>::reset;

        // methods called on the object referenced by the underlying shared_ptr
        void foo();
    };
private:
    explicit A()
    {}
    A(::std::string, int)
    {}
    A(const A &) = delete;
    const A &operator =(const A &) = delete;
public:
    template <typename... T>
    static HiddenSharedPointer create(T &&...args)
    {
        return HiddenSharedPointer(::std::forward<T>(args)...);
    }

    void foo()
    {
    }
};

void A::HiddenSharedPointer::foo()
{
    std::shared_ptr<A>(*this)->foo();
}

template<typename... Args>
A::HiddenSharedPointer::HiddenSharedPointer(Args&&... args)
    : std::shared_ptr<A>(new A(std::forward<Args>(args)...))
{}

std::list<std::pair<A::HiddenSharedPointer, int>> m_ok;

int main()
{
    A::HiddenSharedPointer temp = A::create();
    temp.foo();
    //auto plain_pointer_to_object = temp.get(); // does not compile
    m_ok.push_back(std::pair<A::HiddenSharedPointer, int>(temp, 10));

    temp.reset();

    return 0;
}

请注意,我将地图更改为成对列表,因为如果使用地图,则必须为HiddenSharedPointer类提供operator <。 无论如何,使用(共享)指针作为地图的键不是一个好主意,因为这会带来不确定的行为(即,在每次运行中,您的地图具有不同的顺序)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM