要求
RCObject
的类,它表示“引用计数对象”; RCObject
类应该是抽象的,用作框架的基类(EC++3项目7); RCObject
子类的实例(MEC++1项目27);[添加:]
[假定
Bear
是RCObject
的具体子类][这里的
C.E.
表示编译错误]Bear b1; // Triggers C.E. (by using MEC++1 Item 27)
Bear* b2; // Not allowed but no way to trigger C.E.
intrusive_ptr<Bear> b3; // Recommended
Bear* bs1 = new Bear[8]; // Triggers C.E.
container< intrusive_ptr<RCObject> > bs2; // Recommended
intrusive_ptr_container<RCObject> bs3; // Recommended
class SomeClass {
private:
Bear m_b1; // Triggers C.E.
Bear* m_b2; // Not allowed but no way to trigger C.E.
intrusive_ptr<Bear> m_b3; // Recommended
};
RCObject
(和子类)的原始指针(不幸的是,我不认为存在强制实现它的实际方法,即,当用户不遵循时触发编译错误)。参见上面第3项中的示例源代码; RCObject
一样,Cloneable
子类的实例应该是可克隆的。 (MEC++1项目25); RCObject
的用户应该能够为其子类编写"Factory Methods"。即使返回值被忽略(未分配给变量),也不应有内存泄漏。与之接近的机制是Objective-C中的autorelease
;[添加: cschwan和Kos指出,返回“smart-pointer-to-
RCObject
”足以满足要求。 ] RCObject
子类的实例应能够包含在适当的std::
或boost::
容器中。我主要需要一个“类似于std::vector
的”容器,一个“类似于std::set
的”容器和一个“类似于std::map
的”容器。基线是intrusive_ptr<RCObject> my_bear = v[10];
和
m["John"] = my_bear;
按预期工作;
更多信息
intrusive_ptr
而不是 shared_ptr
,但是我对两者都持开放态度,甚至对其他建议也持开放态度。 make_shared()
, allocate_shared()
, enable_shared_from_this
()是否可以帮助(顺便说一句,在Boost中, enable_shared_from_this
()似乎没有得到很大的 boost -甚至在smart pointer主页中也找不到)。 RCObject
是否应该从 boost::noncopyable
私下继承; intrusive_ptr_add_ref()
和intrusive_ptr_release()
以及如何使用Argument-Dependent Lookup (aka. Koenig Lookup)来实现它们; boost::atomic_size_t
与boost:intrusive_ptr
一起使用。 类定义
namespace zoo {
class RCObject { ... }; // Abstract
class Animal : public RCObject { ... }; // Abstract
class Bear : public Animal { ... }; // Concrete
class Panda : public Bear { ... }; // Concrete
}
“非智能”版本-createAnimal()[工厂方法]
zoo::Animal* createAnimal(bool isFacingExtinction, bool isBlackAndWhite) {
// I wish I could call result->autorelease() at the end...
zoo::Animal* result;
if (isFacingExtinction) {
if (isBlackAndWhite) {
result = new Panda;
} else {
result = new Bear;
}
} else {
result = 0;
}
return result;
}
“非智能”版本-main()
int main() {
// Part 1 - Construction
zoo::RCObject* object1 = new zoo::Bear;
zoo::RCObject* object2 = new zoo::Panda;
zoo::Animal* animal1 = new zoo::Bear;
zoo::Animal* animal2 = new zoo::Panda;
zoo::Bear* bear1 = new zoo::Bear;
zoo::Bear* bear2 = new zoo::Panda;
//zoo::Panda* panda1 = new zoo::Bear; // Should fail
zoo::Panda* panda2 = new zoo::Panda;
// Creating instances of RCObject on the stack should fail by following
// the method described in the book MEC++1 Item 27.
//
//zoo::Bear b; // Should fail
//zoo::Panda p; // Should fail
// Part 2 - Object Assignment
*object1 = *animal1;
*object1 = *bear1;
*object1 = *bear2;
//*bear1 = *animal1; // Should fail
// Part 3 - Cloning
object1 = object2->clone();
object1 = animal1->clone();
object1 = animal2->clone();
//bear1 = animal1->clone(); // Should fail
return 0;
}
“智能”版本[未完成!]
/* TODO: How to write the Factory Method? What should be returned? */
#include <boost/intrusive_ptr.hpp>
int main() {
// Part 1 - Construction
boost::intrusive_ptr<zoo::RCObject> object1(new zoo::Bear);
boost::intrusive_ptr<zoo::RCObject> object2(new zoo::Panda);
/* ... Skip (similar statements) ... */
//boost::intrusive_ptr<zoo::Panda> panda1(new zoo::Bear); // Should fail
boost::intrusive_ptr<zoo::Panda> panda2(new zoo::Panda);
// Creating instances of RCObject on the stack should fail by following
// the method described in the book MEC++1 Item 27. Unfortunately, there
// doesn't exist a way to ban the user from declaring a raw pointer to
// RCObject (and subclasses), all it relies is self discipline...
//
//zoo::Bear b; // Should fail
//zoo::Panda p; // Should fail
//zoo::Bear* pb; // No way to ban this
//zoo::Panda* pp; // No way to ban this
// Part 2 - Object Assignment
/* ... Skip (exactly the same as "non-smart") ... */
// Part 3 - Cloning
/* TODO: How to write this? */
return 0;
}
上面的代码(“智能版本”)显示了预期的使用模式。我不确定这种使用模式是否遵循使用智能指针的最佳实践。如果没有,请纠正我。
类似问题
intrusive_ptr
相比)make_shared()
和 enable_shared_from_this
(),但我不理解“但是不允许您使用不同的智能指针类型来管理类型”部分)zoo::Panda
单独从zoo::Bear
扩展,还是应该让它同时扩展zoo::Bear
和intrusive_base<zoo::Panda>
?)std::enable_shared_from_this()
应该可以,但 boost::enable_shared_from_this()
似乎有一些问题)引用文献
文章
boost::atomic
的用法示例-Boost.org最佳答案
make_shared
在与引用计数器相同的分配块中创建类的实例。我不确定为什么您认为intrusive_ptr
会具有更好的性能:当已经有无法删除的引用计数机制时,这很棒,但是在这里情况并非如此。
对于克隆,我将其实现为一个自由函数,该函数需要一个智能指针并返回相同的指针。它是一个 friend ,并在base中调用私有(private)的纯虚拟克隆方法,该方法将共享指针返回至base,然后将快速智能指针强制转换为对派生对象的共享指针。如果您希望使用克隆作为方法,请使用crtp来复制它(为私有(private)克隆提供一个名称,例如secret_clone
)。这为您提供了协变智能指针返回类型,而开销却很小。
具有一系列基类的Crtp通常会同时传递基类和派生类。crtp类是从基类派生的,并具有返回派生的通常的self()
。
工厂函数应返回智能指针。您可以使用自定义删除器技巧来获得销毁前的方法调用以进行最后的清理。
如果您完全偏执,则可以阻止大多数方法来获取原始指针或对类的引用:智能指针上的block operator *。然后,到达原始类的唯一途径是对operator->
的显式调用。
要考虑的另一种方法是unique_ptr
及其引用。您需要共享所有权和终身管理吗?确实使一些问题变得更简单(共享所有权)。
请注意,悬空的弱指针会阻止使内存共享共享带回。
始终使用智能指针的严重缺点是,不能在容器内部直接具有堆栈实例或实例。两者都可以极大地 boost 性能。
关于c++ - 与智能指针(intrusive_ptr)一起使用的抽象基类-处理继承,多态性,可克隆性以及从工厂方法返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15474684/