Poco::AutoPtr是一个含有引用计数的“智能”指针模版。
Poco::AutoPtr用于支持引用计数的类实例化。支持引用计数的类需要有以下要求:
Poco::AutoPtr支持完整的值语义(默认构造函数、复制构造函数、赋值),可以在集合中使用
(例如std::vector或std::map)。
使用Poco::AutoPtr::isNull()或Poco::AutoPtr::operator !()来测试是否为空
AutoPtr强制转换总是类型安全的(内部使用了dynamic_cast,因此无效的强制转换将导致空指针)。
AutoPtr::AutoPtr(C* pObject, bool shared); // shared=true,表示为共享指针
下面的示例中 RCO 维护一个引用计数_rc,在创建时,将_rc赋值为1,然后实现两个方法duplicate和release,示例源码如下:
#include "Poco/AutoPtr.h"
using Poco::AutoPtr;
class RCO
{
public:
RCO(): _rc(1){}
void duplicate()
{
++_rc; // Warning: not thread safe!
}
void release()
{
if (--_rc == 0) delete this; // Warning: not thread safe!
}
private:
int _rc;
};
int main(int argc, char** argv)
{
RCO* pNew = new RCO; // _rc == 1
AutoPtr<RCO> p1(pNew); // _rc == 1
AutoPtr<RCO> p2(p1); // _rc == 2
AutoPtr<RCO> p3(pNew, true); // _rc == 3
p2 = 0; // _rc == 2
p3 = 0; // _rc == 1
RCO* pRCO = p1; // _rc == 1
p1 = 0; // _rc == 0 -> deleted
// pRCO and pNew now invalid!
p1 = new RCO; // _rc == 1
return 0;
} // _rc == 0 -> deleted
Poco::RefCountedObject 实现线程安全的引用计数语义。从poco-1.3.4版本开始,它使用特定于平台的原子操作。
Poco::RefCountedObject可以用作实现引用计数的类的基类。
Poco::RefCountedObject有一个受保护的析构函数,禁止复制构造和赋值。
所有引用计数的对象都应该有一个受保护的析构函数,以禁止显式使用delete。
#include "Poco/RefCountedObject.h"
#include "Poco/AutoPtr.h"
#include
using Poco::RefCountedObject;
using Poco::AutoPtr;
class RCO: public RefCountedObject
{
public:
RCO(){}
void greet() const
{
std::cout << "Hello, world!" << std::endl;
}
protected:
~RCO(){}
};
int main(int argc, char** argv)
{
AutoPtr<RCO> pRCO(new RCO);
pRCO->greet(); // AutoPtr has -> operator
(*pRCO).greet(); // AutoPtr has * operator
std::cout << "refcount: " << pRCO->referenceCount() << std::endl;
RCO* p1 = pRCO; // AutoPtr supports conversion to plain pointer
RCO* p2 = pRCO.get();
return 0;
}
Poco::AutoReleasePool获取添加到它的每个对象的所有权
当Poco::AutoReleasePool被销毁(或者它的release()方法被调用)时,它通过调用每个对象的release()方法释放对它持有的所有对象的引用。
#include "Poco/AutoReleasePool.h"
using Poco::AutoReleasePool;
class C
{
public:
C(){}
void release() {delete this;}
};
int main(int argc, char** argv)
{
AutoReleasePool<C> pool;
C* pC = new C;
pool.add(pC);
pC = new C;
pool.add(pC);
return 0;
}
// 两次new的C,都将被销毁
Poco::AutoPtr用于类自身含有引用计数的对象;
Poco::SharedPtr为普通类实现引用计数(自身不需要实现引用计数的类)
头文件:#include “Poco/SharedPtr.h”
警告:将同一个普通指针分配给不同的Poco::SharedPtr将导致该对象有多个所有者,从而导致未定义的行为(换句话说,崩溃)。
一旦对一个对象使用了Poco::SharedPtr,就不要再使用指向那个对象的普通指针了
Poco::SharedPtr支持完整的值语义(默认构造函数、复制构造函数、赋值),并可用于集合(例如std::vector或std::map)。
使用SharedPtr::isNull()或SharedPtr::operator !()来测试是否为空
#include "Poco/SharedPtr.h"
#include
#include
using Poco::SharedPtr;
int main(int argc, char** argv)
{
std::string* pString = new std::string("hello, world!");
Poco::SharedPtr<std::string> p1(pString); // rc == 1
Poco::SharedPtr<std::string> p2(p1); // rc == 2
p2 = 0; // rc == 1
// p2 = pString; // 崩溃: 多个所有者
p2 = p1; // rc == 2
std::string::size_type len = p1->length(); // 使用“->”解引用
std::cout << *p1 << std::endl; // 使用“*”解引用
return 0;
}
Poco::SharedPtr的默认实现将简单地调用delete pObj
用new[]创建的对象,默认使用delete 肯定会出错,因为释放时,需要调用delete[] pObj
可以在创建Poco::SharedPtr时,使用自定义释放策略
模版如下:
Poco::SharedPtr
使用示例
template <class C>
class ArrayReleasePolicy
{
public:
static void release(C* pObj) {delete [] pObj;}
};
char* pStr = new char[100];
Poco::SharedPtr<char, Poco::ReferenceCounter, ArrayReleasePolicy> p(pStr);
Poco::DynamicFactory支持按“name”名称创建对象。
头文件:#include “Poco/DynamicFactory.h”
Poco::DynamicFactory管理的所有类必须有一个共同的基类。
Poco::DynamicFactory为基类实例化。
C* Poco::DynamicFactory::createInstance(const std::string& name) const;创建具有给定名称的子类的实例。
要做到这一点,类和它们的实例化器(工厂类)必须在Poco::DynamicFactory中注册
#include "Poco/DynamicFactory.h"
#include "Poco/SharedPtr.h"
using Poco::DynamicFactory;
using Poco::SharedPtr;
class Base {};
class A: public Base{};
class B: public Base{};
int main(int argc, char** argv)
{
DynamicFactory<Base> factory;
# a)注册
factory.registerClass<A>("A");
factory.registerClass<B>("B");
# b)使用工厂来创建
SharedPtr<Base> pA = factory.createInstance("A");
SharedPtr<Base> pB = factory.createInstance("B");
# c)取消注册
factory.unregisterClass("B");
# d)检查是否存在
bool haveA = factory.isClass("A"); // true
bool haveB = factory.isClass("B"); // false (已取消注册)
bool haveC = factory.isClass("C"); // false (没有注册过)
return 0;
}
使用Poco::DynamicFactory工厂方法来创建类,类必须有默认构造函数,如果没有,需要Poco::Instantiator来辅助实现。
#include "Poco/DynamicFactory.h"
using Poco::DynamicFactory;
using Poco::AbstractInstantiator;
class Base {};
class A: public Base {};
class C: public Base
{
public:
C(int i): _i(i){}
private:
int _i;
};
class CInstantiator: public AbstractInstantiator<Base>
{
public:
CInstantiator(int i): _i(i){}
Base* createInstance() const { return new C(_i);}
private:
int _i;
}
int main(int argc, char** argv)
{
DynamicFactory<Base> factory;
factory.registerClass<A>("A");
factory.registerClass("C", new CInstantiator(42));
return 0;
}
当与遗留的C库或操作系统调用接口时,通常需要提供一定大小的缓冲区。
如果缓冲区大于几个字节,则必须在堆上分配。
这需要某种类型的内存管理,以确保缓冲区在不再使用时被删除,即使在异常的情况下。
std::auto_ptr或Poco::SharedPtr(具有默认的发布策略)不能在这里使用,因为它们不适用于数组。
Poco::Buffer可用于提供固定大小的缓冲区(数组),该缓冲区在堆上分配,并在Buffer对象超出作用域时自动删除。
头文件:#include “Poco/Buffer.h”
#include
#include
#include
using Poco::Buffer;
int main(int argc, char** argv)
{
Buffer<char> buffer(1024);
std::cin.read(buffer.begin(), buffer.size());
std::streamsize n = std::cin.gcount();
std::string s(buffer.begin(), n);
std::cout << s << std::endl;
return 0;
}
许多应用程序需要非常频繁地分配和释放给定大小的缓冲区。
在堆上分配缓冲区会影响性能,并可能导致堆碎片。
因此,一旦缓冲区被分配,重用它是有意义的。
Poco::MemoryPool 是一个内存池,一次分配,多次使用,维护一定大小的内存块集合
#include "Poco/MemoryPool.h"
#include
#include
using Poco::MemoryPool;
int main(int argc, char** argv)
{
MemoryPool pool(1024); // unlimited number of 1024 byte blocks
// MemoryPool pool(1024, 4, 16); // at most 16 blocks; 4 preallocated
char* buffer = reinterpret_cast<char*>(pool.get());
std::cin.read(buffer, pool.blockSize());
std::streamsize n = std::cin.gcount();
std::string s(buffer, n);
pool.release(buffer);
std::cout << s << std::endl;
return 0;
}
POCO提供了一个POCO::SingletonHolder类,帮助对延迟创建的单例进行线程安全管理。
头文件:#include “Poco/SingletonHolder.h”
单例实例在第一次被请求时创建在堆上。
当应用程序终止时,单例实例被销毁。
#include "Poco/SingletonHolder.h"
class MySingleton
{
public:
MySingleton(){// ...}
~MySingleton(){// ...}
// ...
static MySingleton& instance()
{
static Poco::SingletonHolder<MySingleton> sh;
return *sh.get();
}
}