C++ 如何避免指针与共享\u ptr挂起?

C++ 如何避免指针与共享\u ptr挂起?,c++,c++11,memory-management,stl,smart-pointers,C++,C++11,Memory Management,Stl,Smart Pointers,我有一个类,其对象指针将作为键/数据添加到内部实现的多个std::map/std::unordered_map/hash中。为了自动删除对象,我正在使用shared_ptr 我用class设计了我的类 现在,我想确保将来不会有人这样做: #include <memory> #include <string> class A { protected: struct this_is_private; public: explicit A(const thi

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

我用class设计了我的类

现在,我想确保将来不会有人这样做:

#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
}
如何避免指针与共享\u ptr挂起

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

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

<> P>没有C++语言的特性,它除了阻止对对象的完全访问之外,还可以防止对象的地址和存储对象。获取地址的程序员始终有责任确保其生命周期是——并且在未来也将是——他们所期望的。更改对象生命周期的程序员有责任确保任何东西都不依赖于更改的生命周期

有一些编程错误,它们被设计成不让程序员直接访问对象的地址,从而使这类错误成为不可能。C++不是其中的一种语言。 如何避免指针与共享\u ptr挂起

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

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

<> P>没有C++语言的特性,它除了阻止对对象的完全访问之外,还可以防止对象的地址和存储对象。获取地址的程序员始终有责任确保其生命周期是——并且在未来也将是——他们所期望的。更改对象生命周期的程序员有责任确保任何东西都不依赖于更改的生命周期


有一些编程错误,它们被设计成不让程序员直接访问对象的地址,从而使这类错误成为不可能。C++不是其中的一种语言。

在包装类HIDENSydDeDeCype中隐藏SydRyPtR,这样类的用户就不能直接访问对象。
#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类提供运算符<。无论如何,使用共享指针作为映射的键不是一个好主意,因为这会造成不确定性行为。E在每次跑步中,地图的顺序都不同

在包装类HiddenSharedPointer中隐藏共享\u ptr,这样类的用户就不能直接访问对象

#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类提供运算符<。无论如何,使用共享指针作为映射的键不是一个好主意,因为这会造成不确定性行为。E在每次跑步中,地图的顺序都不同

人们总是能够创建指向现有对象的原始指针。您已经使不使用create函数就无法创建A。如果有人真的想射中自己的脚,你不能阻止他们。就像super说的,你不能阻止人们射中自己的脚。但是,您可以做的一件事是有一个良好的代码检查过程,并要求在创建指针时使用make_unique和make_shared。您可以编写一个包装类,包装存储在内部的共享ptr。但最终,人们也可以接受/存储这方面的指针。更不用说,只需取消对共享\u ptr的引用,您就可以轻松地存储对的引用,这是不可能避免的,你想阻止人们获取指向类A对象的原始指针吗?你可以删除操作符&对于你的类,这样可以防止任何人以简单的方式获取它的地址,当然,还有std::shared_ptrPeople始终能够生成指向现有对象的原始指针。您已经使不使用create函数就无法创建A。如果有人真的想射中自己的脚,你不能阻止他们。就像super说的,你不能阻止人们射中自己的脚。但是,您可以做的一件事是有一个良好的代码检查过程,并要求在创建指针时使用make_unique和make_shared。您可以编写一个包装类,包装存储在内部的共享ptr。但最终,人们也可以接受/存储这方面的指针。更不用说你只需要一个
s只需取消引用共享的\u ptr,就可以轻松存储对A的引用,这是不可能避免的。为了澄清您的问题:更一般地说,您是否希望防止人们获取指向类A对象的原始指针?您可以删除运算符,以防止任何人以简单的方式获取其地址,当然,还有std::shared\u ptrYou可以实现operator->来返回底层指针,但可以立即对其重新应用->。这比隐藏每个方法的工作量要少,但我承认它确实为GetThis方法留下了空间,这将暴露实际的原始指针。获取这一切似乎很愚蠢,但GetAsAThingy是一种避免动态_cast成本的常用方法。您可以实现操作符->来返回底层指针,但立即对其重新应用->即可。这比隐藏每个方法的工作量要少,但我承认它确实为GetThis方法留下了空间,这将暴露实际的原始指针。获取这一切似乎很愚蠢,但获取AsAsThingy是避免动态角色转换成本的常用方法。