我决定研究Head First Design Patterns的Java代码/将其转换为C++ 11,由于有了智能指针,我能够使用自动内存管理来实现大多数模式。但是,我对其中一个示例有疑问。这是我的代码:
#include <iostream>
#include <memory>
class AbstractBase {
public:
virtual void foo() = 0;
virtual ~AbstractBase() = default;
};
class A : public AbstractBase {
public:
void foo() override { std::cout << "Class A: foo() called" << std::endl; }
};
class B : public AbstractBase {
public:
void foo() override { std::cout << "Class B: foo() called" << std::endl; }
};
class FooDecorator : public AbstractBase {
public:
FooDecorator(AbstractBase *pBase): mpBase(pBase) { }
void foo() override
{
mpBase->foo();
++mNumberOfFooCalls;
}
static int getFooCalls() { return mNumberOfFooCalls; }
private:
static int mNumberOfFooCalls;
AbstractBase *mpBase;
};
class AbstractFactory {
public:
virtual std::unique_ptr<AbstractBase> createA() = 0;
virtual std::unique_ptr<AbstractBase> createB() = 0;
virtual ~AbstractFactory() = default;
};
class CountingFactory : public AbstractFactory {
public:
std::unique_ptr<AbstractBase> createA()
{
// auto pA = new A();
// return std::unique_ptr<AbstractBase>(new FooDecorator(pA));
std::unique_ptr<AbstractBase> pA(new A());
return std::unique_ptr<AbstractBase>(new FooDecorator(pA.get()));
}
std::unique_ptr<AbstractBase> createB()
{
// auto pB = new B();
// return std::unique_ptr<AbstractBase>(new FooDecorator(pB));
std::unique_ptr<AbstractBase> pB(new B());
return std::unique_ptr<AbstractBase>(new FooDecorator(pB.get()));
}
};
int FooDecorator::mNumberOfFooCalls = 0;
int main()
{
std::unique_ptr<AbstractFactory> pFactory(new CountingFactory());
std::unique_ptr<AbstractBase> pObjA = pFactory->createA();
std::unique_ptr<AbstractBase> pObjB = pFactory->createB();
pObjA->foo();
pObjB->foo();
std::cout << "Foo called " << FooDecorator::getFooCalls()
<< " times." << std::endl;
}
该代码的本质是:有两个派生类
A
和B
;它们每个都有一个单一的成员函数,显示被调用的成员函数。还有一个称为FooDecorator
的装饰器,可增加对foo()
进行的调用计数的功能。除了这些,还有
CountingFactory
可用于直接获取装饰对象。在主体部分,使用该工厂,我创建了一个
A
实例和一个B
实例。然后从每个调用foo()
。当我使用clang 3.5编译此代码并运行它时,我没有得到任何错误,但是结果与预期的有所不同,因为它两次调用了
B::foo()
:Class B: foo() called
Class B: foo() called
Foo called 2 times.
另一方面,当我使用gcc 4.9.2编译代码并运行它时,出现以下错误:
pure virtual method called
terminate called without an active exception
看来问题出在
unique_ptr
中的CountingFactory
。我的理解是,用于初始化装饰对象的指针被释放,并且导致未定义的行为(lang情况)或终止(gcc情况)。结果,我决定使用原始指针,并添加了(以上注释)行:
auto pA = new A();
return std::unique_ptr<AbstractBase>(new FooDecorator(pA));
auto pB = new B();
return std::unique_ptr<AbstractBase>(new FooDecorator(pB));
这样做,事情就成功了,我从两个编译器中都得到了预期的输出。但是,现在发生了内存泄漏,必须删除分配。
几乎总是找到了解决此类问题的灵巧指针的解决方案,因此,我正在努力找到解决该问题的最佳方法。我也尝试用
unique_ptr
替换shared_ptr
,但是无济于事,它没有用。我仍然可以采用其他方法摆脱智能指针的困扰吗?还是我必须手动管理在工厂内部分配的内存(不是首选)?
最佳答案
据我了解,您需要FooDecorator
才能拥有pBase
的所有权。您可以通过更改来实现
AbstractBase *mpBase;
至
std::unique_ptr<AbstractBase> mpBase;
因此,您可以像这样在
FooDecorator
中创建CountingFactory
:return std::unique_ptr<AbstractBase>(new FooDecorator(new A()));
或在C++ 14中:
return std::make_unique<FooDecorator>(new A());