将智能指针引入遗留项目
我正在更改一些遗留代码,以便使用智能指针。
我们的项目早于 boost,因此我们有一个现有的侵入式智能指针类(API 见下文)。
我想删除对这些类型的 delete
的显式调用,那么找到它们的最佳方法是什么?
例如:
class A : public RefCount // RefCount added to manage lifetime
{
// ...
};
// typedef A * APtr; => Previous implementation
typedef SPtr<A> APtr;
void deleteObjects (APtr a)
{
delete a; // Want to find this (ideally with compile error)
}
与智能指针一起使用的所有类型都派生自保留引用计数的基类,并且正是该类应负责在计数达到零时删除对象。
我已将我今天正在做的事情添加为答案< /a>,但是,该方法不适用于调用层次结构中的删除。我正在寻找一种完整的解决方案,可以捕获任何对删除的显式调用(来自 RefCount 成员的调用除外)。
智能指针类有以下成员:
template <typename B>
class SPtr
{
public:
// Ctor
SPtr () throw ();
SPtr (B * b) throw ();
SPtr (const SPtr & bptr) throw ();
// Copy Asgn
SPtr & operator = (B * b);
SPtr & operator = (const SPtr & bptr);
// Dtor
~SPtr () throw ();
// Access
bool isSet () const;
B * pointer () const;
B * operator -> () const;
B & operator * () const;
operator void const * () const;
};
I'm changing some legacy code so that is uses smart pointers.
Our projects pre-date boost and so we have an existing intrusive smart pointer class (see below for API).
I want to remove explicit calls to delete
for these types, so what is the best way to find them?
For example:
class A : public RefCount // RefCount added to manage lifetime
{
// ...
};
// typedef A * APtr; => Previous implementation
typedef SPtr<A> APtr;
void deleteObjects (APtr a)
{
delete a; // Want to find this (ideally with compile error)
}
All types that are to be used with the smart pointer derive from a base class that keeps a reference count, and it is this class that should be responsible for deleting the object when the count reaches zero.
I've added what I'm doing today as an answer, however, the approach doesn't work for calls to delete in hierarchies. I am looking for a complete solution that catches any explicit call to delete (other than the one from the RefCount member).
The smart pointer class has the following members:
template <typename B>
class SPtr
{
public:
// Ctor
SPtr () throw ();
SPtr (B * b) throw ();
SPtr (const SPtr & bptr) throw ();
// Copy Asgn
SPtr & operator = (B * b);
SPtr & operator = (const SPtr & bptr);
// Dtor
~SPtr () throw ();
// Access
bool isSet () const;
B * pointer () const;
B * operator -> () const;
B & operator * () const;
operator void const * () const;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将模板类
SPtr
的析构函数设为私有。这将导致调用delete a;
时出错,其中 a 的类型为SPtr
,其中 T 为任意类型。另一种解决方案是重载
delete
和delete[]
运算符并将它们设为私有。在这种情况下,您仍然可以在堆栈上创建类,但调用删除将导致错误。例如:Make a destructor of template class
SPtr
private. This will result in an error callingdelete a;
where a is of typeSPtr<T>
where T is arbitrary type.Another solution would be to overload
delete
anddelete[]
operators and make them private. In that case, you still could create class on stack, but calling a delete will result in error. For example:在你的智能指针类中去掉
operator void const * () const;
就可以了。从智能指针到原始指针的隐式转换通常隐藏了许多不值得实现的问题。即使使用转换运算符,我仍然在 g++ 中收到警告,并发布了代码。
Get rid of
operator void const * () const;
in your smart pointer class and that should do it. Implicit conversions from smart pointer to raw pointer generally hide so many problems it's not worth implementing.Even with the conversion operator I still got a warning in g++ with the code as posted.
捕获除层次结构内的情况之外的情况的技术是临时使用placement new 和delete:
有必要使用placement new,作为调用
operator new
的operator delete
code> 分配对象时必须可访问(以防引发异常)。因此,为了能够调用new A
,我们需要operator new
和operator delete
。标准中的规则意味着针对这种情况调用的
operator delete
与operator new
相匹配,因此附加默认参数要求operator delete(void* , size_t)
在分配时可访问,而不是operator delete(void*)
。然而,示例中所示的缺点是派生类仍然需要可访问
operator delete(void*)
。这只是临时更改,一旦找到并删除所有对删除的调用,就应该删除重载。
A technique that catches cases except those from within the hierarchy is to temporarily use placement new and delete:
It is necessary to use placement new, as the
operator delete
for a call tooperator new
must be accessible when allocating an object (in case an exception is thrown). Therefore, in order to be able to callnew A
we need both anoperator new
and andoperator delete
.The rules in the standard mean that the
operator delete
that's called for this situation matches theoperator new
, and so the additional default parameter requires thatoperator delete(void*, size_t)
be accessible when allocating and notoperator delete(void*)
.The drawback as shown in the example, however, is that derived classes still require that
operator delete(void*)
be accessible.This is a temporary change only, once all calls to delete have been found and removed, the overloads should be removed.