簡體   English   中英

在C ++中實現Abstract Factory PIMPL成語的運行時錯誤

[英]Runtime error implementing Abstract Factory PIMPL Idiom in C++

嘗試在PIMPL慣用法下實現抽象工廠時,嘗試從Factory范圍之外獲取對象時遇到運行時錯誤。 (請參閱Main中注釋為“運行時錯誤”的部分。當從公共類中調用AcquisitionInterface()方法時,會發生這種情況,該方法從實現中調用AcquisitionInterface())。 但是,當在實現類中通過testFactory()函數的AcquisitionInterface()時,不會發生這種情況(請參見“ testFactory()”函數)。 有什么建議嗎? 在啟用RTTI的MinGW 4.8和VC ++ 11中進行了嘗試。

提前致謝。

---文件:IType.hpp-

#ifndef ITYPE_HPP_
#define ITYPE_HPP_


class ITYPE {
public:
    ITYPE() {
        std::cout << "ITYPE()" << std::endl;
    };
    virtual ~ITYPE(){
        std::cout << "~ITYPE()" << std::endl;
    };
    virtual void hello() = 0;
};


#endif /* ITYPE_HPP_ */

---文件:Factory.hpp-

#ifndef FACTORY_HPP
#define FACTORY_HPP

#include <memory>
#include <iostream>

#include "IType.hpp"

class Factory {
public:
    Factory();
    ~Factory();

    void testFactory();

    ITYPE* acquireInterface(const char* type);

private:
    class Impl;
    std::unique_ptr<Impl> m_pimpl;
};

#endif //FACTORY_HPP

---文件:FactoryImpl.cpp-

// Implementations
// ----------------------------------------------------------------------

class ConcreteA : public ITYPE {
public:
    ConcreteA(){ std::cout << "ConcreteA()" << std::endl; }
    ~ConcreteA(){ std::cout << "~ConcreteA()" << std::endl; }

    void hello() { std::cout << "A says Hello" << std::endl; }
};

class ConcreteB : public ITYPE {
public:
    ConcreteB(){ std::cout << "ConcreteB()" << std::endl; }
    ~ConcreteB(){ std::cout << "~ConcreteB()" << std::endl; }
    void hello() { std::cout << "B says Hello" << std::endl; }
};


// ----------------------------------------------------------------------


template<typename Type> ITYPE* createType()
{
    return new Type();
}

/**
 * @brief Abstract Factory for ITYPES.
 */
class Factory::Impl {
    public:
        /**
         * @brief Constructor
         * @details Implementations to be added here using function addType()
         */
        Impl() {
            addType<ConcreteA>("A");
            addType<ConcreteB>("B");
        };

        ITYPE* acquireInterface(const char* type)
        {           
            std::cout << "Acquiring interface for " << type << "..." << std::endl;
            Impl::map_type::iterator iter = m_map.find(type);
            return iter->second();      
        }

    // THIS WORKS
    void testFactory()
    {
        ITYPE* iA = acquireInterface("A");
        iA->hello();
        delete iA;

        ITYPE* iB = acquireInterface("B");
        iB->hello();
        delete iB;
    }

    private:
        /** @brief Adds a type to the Abstract Factory
         *  @param componentName short string (no spaces) to identify implementation */
        template<typename Type>
        void addType(const char* componentName) {
            ComponentFactoryFuncPtr function = createType<Type>;
            m_map.insert(std::make_pair(componentName, function));
        };

public:
        /**
         * @brief Abstract factory constructor function pointer
         */
        typedef  ITYPE* (*ComponentFactoryFuncPtr)();

        /**
         * @brief Type for map holding type identifier / constructor function
         */
        typedef std::map<const char*, ComponentFactoryFuncPtr> map_type;

private:
     map_type m_map;    /**< map holding type identifier / constructor function */
};

Factory::Factory() : m_pimpl(new Impl()) { }

Factory::~Factory() { }

void Factory::testFactory()
{
    m_pimpl->testFactory();
}

ITYPE* Factory::acquireInterface(const char* type)
{
    return m_pimpl->acquireInterface(type);
}

-主要-

#include <iostream>
#include <memory>
using namespace std;

#include "Factory.hpp"

int main() 
{
    {
        Factory f;

        // OK
        std::cout << "This works:"  << std::endl;
        f.testFactory();

        // Runtime error (acquireInterface("A") returns NULL ptr)
        ITYPE* iA = f.acquireInterface("A");
        iA->hello();
        delete iA;

        ITYPE* iB = f.acquireInterface("B");
        iB->hello();
        delete iB;
    }

    return getchar();
}

代碼中的一件壞事是:

typedef std::map<const char*, ComponentFactoryFuncPtr> map_type;

主要問題是,即使字面量相同,您也不能保證const char*字面量將具有相同的地址。

您的代碼嘗試這樣做:

ITYPE* iA = f.acquireInterface("A");

不能保證字符串字面量"A"的指針值與您用來設置地圖的"A"相同。 因此,對於即將發生的事情,行為是不確定的。

如果map鍵的目標是使用字符串,請使用字符串。 現在,您可以完全控制鍵所代表的內容,而不是const char * ,在這里您並不真正知道編譯器將如何處理字符串文字。 您真正真正知道的是"A"是字符串文字,但這就是您真正能知道的。

解決方法是這樣的:

typedef std::map<std::string, ComponentFactoryFuncPtr> map_type;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM