我决定研究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;
}

该代码的本质是:有两个派生类AB;它们每个都有一个单一的成员函数,显示被调用的成员函数。还有一个称为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());

08-27 13:32