【发布时间】:2021-04-27 06:16:52
【问题描述】:
我有两个课,
template<class Type>
class SafePtr {
public:
SafePtr() {}
~SafePtr() {}
void Lock(Type* data, void* key)
{
if (!pKey)
{
pKey = key;
pData = data;
}
}
Type* Unlock(void* key) const
{
if (key == pKey)
return pData;
}
Type* operator->()
{
return pData;
}
private:
Type* pData = nullptr;
void* pKey = nullptr;
};
template<class Type>
class SafePtrArray {
public:
SafePtrArray() {}
~SafePtrArray() {}
template<class... Args>
SafePtr<Type> CreatePtr(Args&&... args)
{
Type* data = new Type(args...);
ptrs.insert(ptrs.end(), data);
SafePtr<Type> ptr;
ptr.Lock(data, this);
return ptr;
}
Type* UnlockPtr(const SafePtr<int>& ptr)
{
return ptr.Unlock(this);
}
void Destroy(const SafePtr<int>& ptr)
{
Type* pointer = ptr.Unlock(this);
for (auto itr = ptrs.begin(); itr != ptrs.end(); itr++)
{
if ((*itr) == pointer)
{
delete pointer;
ptrs.erase(itr);
}
}
}
private:
std::vector<Type*> ptrs;
};
解释:
目标是保护指针,以便用户可以访问其成员但不能操作其实际指针(主要是过早地删除它)。而且我还需要将所有指针存储在一个数组中,这样当父对象销毁时,我可以自动销毁所有分配的指针。
为此,我使用了两个类,SafePtr 和 SafePtrArray。 SafePtrArray 创建并存储指针并将它们包装在 SafePtr 中并将其返回给用户。 SafePtr 只是一个包装器,不应让用户访问底层指针,但允许他们访问其成员。
一开始还可以,但很快我就发现了这个错误,
int main()
{
SafePtrArray<int> ptr;
auto pInt = ptr.CreatePtr();
int* i = pInt.operator->(); // Users can get access to the underlying pointer using this.
ptr.Destroy(pInt);
}
所以我的问题是,
有没有办法阻止用户访问底层类型并阻止他们在有权访问其成员的同时操作指针?
【问题讨论】:
-
为什么不直接使用老旧的
shared_ptr及其朋友,让您的用户拥有熟悉的界面? -
你不能以通用的方式做到这一点。你需要那个的原因是什么?对于 stdlib 和其他库中的任何类型,用户通常可以访问他们不能删除的对象(及其指针),因为他们没有这些对象的所有权? (对于
std::shared_ptr,std::unique_ptr,您可以调用get(),对于std::vector(),您可以调用data(),对于std::list,您可以检索元素的指针,...) -
@D-RAJ 好吧,用户仍然可以做
SafePtrArray<int> ptr; delete &ptr;- 这当然是未定义的行为 - 但是删除您不拥有的对象通常也会导致未定义的行为(由于双重释放或访问已删除的对象)。听起来您要么想确保不了解该语言的用户不会做错任何事,要么想绕过代码或文档中可能存在的设计缺陷。 -
鉴于
operator->明确提供了对指针的访问,我认为您的解决方案是停止认为 任何 合理的用户会以这种方式获取指针,而指针显然不是他们的玩,并注销任何会这样做的用户作为白痴。即使您管理了一些可怕的 hack 来启用您想要的行为,它仍然是 C++;他们可以直接访问内存,如果他们愿意,他们可以做可怕的非标准事情来访问该指针; 你的工作是防止意外做错事,让有动力的用户不可能滥用你的 API。 -
典型的 C++ 方法是记录指针的所有权,声明任何删除我的指针的尝试都将导致未定义的行为,并且只是让一个坚定的程序员自取其辱。 C++ 不是一种安全的语言。如果你采用这种思维方式,
std::shared_ptr似乎会做你想做的事——注意它缺少release()方法,不像unique_ptr。
标签: c++ pointers access-protection