Вот ваш шанс выпустить двойной звонок:
void func()
{
MyClass a(resourceA, resourceB);
MyClass b(a);
}
Упс.
Если вы используете оболочку RIAA для своих ресурсов, у вас будет гораздо меньше шансов ошибиться.Это может привести к ошибкам.В настоящее время вам не хватает конструктора копирования и оператора присваивания в MyClass, которые потенциально могут привести к двойному вызову Release (), как показано выше.
Из-за сложности обработки ресурса класс должен владеть только одним ресурсом.Если у вас есть несколько ресурсов, делегируйте их право собственности классу, который он выделил для их владения, и используйте несколько таких объектов в вашем классе.
Редактировать 1
Давайте сделаем некоторые предположения:
Ресурсы распределяются и подсчитываются.Вы увеличиваете счет с помощью Acquire () и уменьшаете счет с помощью Release ().Когда счетчик достигает нуля, они автоматически уничтожаются.
class ReferenceRapper
{
ReferenceBase* ref;
public:
ReferenceWrapper(ReferenceBase* r) : ref (r) {/* Pool set the initial count to 1 */ }
~ReferenceWrapper() { if (ref) { ref->Release();} }
/*
* Copy constructor provides strong exception guarantee (aka transactional guarantee)
* Either the copy works or both objects remain unchanged.
*
* As the assignment operator is implemented using copy/swap it also provides
* the strong exception guarantee.
*/
ReferenceWrapper(ReferenceWrapper& copy)
{
if (copy.ref) {copy.ref->Acquire();}
try
{
if (ref) {ref->Release();}
}
catch(...)
{
if (copy.ref)
{ copy.ref->Release(); // old->Release() threw an exception.
// Must reset copy back to its original state.
}
throw;
}
ref = copy.ref;
}
/*
* Note using the copy and swap idium.
* Note: To enable NRVO optimization we pass by value to make a copy of the RHS.
* rather than doing a manual copy inside the method.
*/
ReferenceWrapper& operator(ReferenceWrapper rhsCopy)
{
this->swap(rhsCopy);
}
void swap(ReferenceWrapper& rhs) throws ()
{
std::swap(ref, rhs.ref);
}
// Add appropriate access methods like operator->()
};
Теперь, когда тяжелая работа выполнена (управление ресурсами).Реальный код становится тривиальным для записи.
class MyClass
{
ReferenceWrapper<SomeResourceA> m_resA;
ReferenceWrapper<SomeResourceB> m_resB;
public:
MyClass(ReferenceWrapper<SomeResourceA>& a, ReferenceWrapper<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
ReferenceWrapper<SomeResourceA> resA(g_pPoolA->Allocate());
ReferenceWrapper<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
Редактировать 2 Исходя из комментария ниже, ресурсы имеют только одного владельца:
Если предположить, что ресурс имеет только одного владельца и не является общим, тоэто становится тривиальным:
- Удалите метод Release () и сделайте всю работу в деструкторе.
- Измените методы пула, чтобы указатель создавался в std :: auto_ptrи вернуть std :: auto_ptr.
Код:
class MyClass
{
std::auto_ptr<SomeResourceA> m_resA;
std::auto_ptr<SomeResourceB> m_resB;
public:
MyClass(std::auto_ptr<SomeResourceA>& a, std::auto_ptr<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
std::auto_ptr<SomeResourceA> resA(g_pPoolA->Allocate());
std::auto_ptr<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}