我有一个类,其对象指针将作为键/数据添加到多个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
}
答案 0 :(得分:4)
如何避免使用shared_ptr悬挂指针?
通过根本不存储指向对象的裸指针(既不引用也不迭代),或者确保此类指针的生存期短于共享指针的生存期。后者的正确性不像前者的正确性容易证明。
如何确保将来没有人[存储裸指针]
除了完全封装对对象的访问权限之外,C ++语言中没有其他功能可以阻止获取对象的地址并将其存储。程序员总是有责任承担地址,以确保生存期是-并且将来将是-他们期望的。更改对象的生存期是程序员的责任,以确保不依赖于更改的生存期。
有些编程language被设计为不允许程序员直接访问对象的地址,从而使此类错误成为不可能。 C ++不是这些语言之一。
答案 1 :(得分:1)
将您的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 <。无论如何,使用(共享的)指针作为映射的键不是一个好主意,因为这强加了不确定的行为(即,在每次运行中,您的映射具有不同的顺序)。