2014-12-03 52 views
2

我在C++中有一箇舊的工廠實現,我想使用唯一指針而不是原始指針。我的代碼的一個最小例子如下。我有一個基類A,以及派生類B。在main()中,我將1轉換爲create方法A,並且b1的類型現在更改爲B在C++中使用unique_ptr的工廠模式

#include <iostream> 
#include <map> 

class A { 
public: 
    A() {} 
    virtual void Foo() {} 
    std::map<int, A *> &registerType() { 
    static std::map<int, A *> map_instance; 
    return map_instance; 
    } 
    A *create(int n) { return registerType()[n]; } 
}; 

class B : A { 
public: 
    B() { registerType()[1] = this; } 
    void Foo() { std::cout << "I am B!\n"; } 
}; 

static B b0; 

int main() { 
    A *b1 = new A(); 
    b1 = b1->create(1); 
    b1->Foo(); 

    return 0; 
} 

現在,如果我想改變原始指針,以獨特的指針,我自然會得到錯誤的集合(下面的代碼導致錯誤):

#include <iostream> 
#include <map> 
#include <memory> 

class A { 
public: 
    A() {} 
    virtual void Foo() {} 
    std::map<int, std::unique_ptr<A>> &registerType() { 
    static std::map<int, std::unique_ptr<A>> map_instance; 
    return map_instance; 
    } 
    std::unique_ptr<A> create(int n) { return registerType()[n]; } 
}; 

class B : A { 
public: 
    B() { registerType()[1](this); } 
    void Foo() { std::cout << "I am B too!\n"; } 
}; 

static B b0; 

int main() { 
    std::unique_ptr<A> b1(new A()); 
    b1 = b1->create(1); 
    b1->Foo(); 

    return 0; 
} 

的錯誤是:

In member function 'std::unique_ptr<A> A::create(int)': 
use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = A; _Dp = std::default_delete<A>]' 
    std::unique_ptr<A> create(int n) { return registerType()[n]; } 

In constructor 'B::B()': 
no match for call to '(std::map<int, std::unique_ptr<A> >::mapped_type {aka std::unique_ptr<A>}) (B* const)' 
    B() { registerType()[1](this); } 
          ^

所以我想知道:

  1. 被打算在像我這樣的情況下使用獨特的指針? (我假設回答應該是!)
  2. 我需要將this作爲unique_ptr類型傳遞給registerType方法。如何將指針的所有權傳遞給當前實例(this關鍵字)以unique_ptr? (如果有可能或有意成爲可能)
  3. 如果在這裏使用唯一指針是一種很好的做法,我應該如何實現它?
+0

_「我自然會收到錯誤集合_」 - 請在您的文章中包含錯誤的全文。隨意忽略多行發生的重複。 – 2014-12-03 22:01:39

+2

我不明白這將如何與'std :: unique_ptr'一起使用。你當然可以將它們存儲在'std :: map'中,並且可以*引用它們。但他們最好被做成*移動*;未複製。將它們從您的地圖中移出將起作用,但是爲什麼還要在第一時間製作地圖。看起來'std :: shared_ptr'會爲你所嘗試的付出更多的紅利(如果配置正確,你也可以設置共享'this') – WhozCraig 2014-12-03 22:10:52

+1

@ a.sam它的寫法非常混亂,你有一個「創建」功能,它不會創建任何內容,並通過執行'b1 = b1-> create(1);' – PeterT 2014-12-03 23:27:46

回答

4

首先,如果有人想實現一個工廠模式,與原始指針做的一種可接受的方式如下:

#include <iostream> 
#include <map> 

class A; 

class A_Factory { 
public: 
    A_Factory() {} 
    virtual A *create() = 0; 
}; 

class A { 
public: 
    A() {} 
    static void registerType(int n, A_Factory *factory) { 
    get_factory_instance()[n] = factory; 
    } 
    static A *create(int n) { 
    A *A_instance = get_factory_instance()[n]->create(); 
    return A_instance; 
    } 
    virtual void setMyID(int n) {} 
    virtual void I_am() { std::cout << "I am A\n"; } 
    virtual ~A() {} 

protected: 
    int MyID; 
    static std::map<int, A_Factory *> &get_factory_instance() { 
    static std::map<int, A_Factory *> map_instance; 
    return map_instance; 
    } 
}; 

class B : public A { 
public: 
    B() {} 
    void Foo() {} 
    void I_am() { std::cout << "I am B " << MyID << "\n"; } 
    void setMyID(int n) { MyID = n; } 
    ~B() {} 

private: 
}; 

class B_Factory : public A_Factory { 
public: 
    B_Factory() { A::registerType(1, this); } 
    A *create() { return new B(); } 
}; 

static B_Factory b0_factory; 

void caller() {} 

int main() { 
    A *b1 = A::create(1); 
    A *b2 = A::create(1); 
    b1->setMyID(10); 
    b2->setMyID(20); 
    b1->I_am(); 
    b2->I_am(); 
    delete b1; 
    delete b2; 

    return 0; 
} 

A是基類,並B是派生一。如果我們通過1A::create(int n),將生成B類型的對象。內存是手動管理的,不會有內存泄漏。

關於在後的問題:

  1. YES。 unique_ptr很棒;儘可能地使用它們!
  2. 隨着問題中提出的設計,通過this的所有權是某種程度上必要的。我想不出一種方式來通過this的所有權。通過答案中提供的設計,沒有必要通過this的所有權。
  3. 在如下上述工廠模式貫徹的unique_ptr:
#include <iostream> 
#include <map> 
#include <memory> 

class A; 

class A_Factory { 
public: 
    A_Factory() {} 
    virtual std::unique_ptr<A> create_unique() = 0; 
}; 

class A { 
public: 
    A() {} 
    static void registerType(int n, A_Factory *factory) { 
    get_factory_instance()[n] = factory; 
    } 
    static std::unique_ptr<A> create_unique(int n) { 
    std::unique_ptr<A> A_instance = 
     std::move(get_factory_instance()[n]->create_unique()); 
    return A_instance; 
    } 

    virtual void setMyID(int n) {} 
    virtual void I_am() { std::cout << "I am A\n"; } 
    virtual ~A() {} 

protected: 
    int MyID; 
    static std::map<int, A_Factory *> &get_factory_instance() { 
    static std::map<int, A_Factory *> map_instance; 
    return map_instance; 
    } 
}; 

class B : public A { 
public: 
    B() {} 
    void Foo() {} 
    void I_am() { std::cout << "I am B " << MyID << "\n"; } 
    void setMyID(int n) { MyID = n; } 
    ~B() {} 

private: 
}; 

class B_Factory : public A_Factory { 
public: 
    B_Factory() { A::registerType(1, this); } 
    std::unique_ptr<A> create_unique() { 
    std::unique_ptr<A> ptr_to_B(new B); 
    return ptr_to_B; 
    } 
}; 

static B_Factory b0_factory; 

void caller() {} 

int main() { 
    std::unique_ptr<A> b1 = std::move(A::create_unique(1)); 
    std::unique_ptr<A> b2 = std::move(A::create_unique(1)); 
    b1->setMyID(10); 
    b2->setMyID(20); 
    b1->I_am(); 
    b2->I_am(); 

    return 0; 
} 

正如你可以看到,無需人工存儲器管理是必要的,並且存儲器管理由unique_ptr處理。