2012-04-02 74 views
1

我對PImpl進行了相當廣泛的使用,並且我發現自己正在揮之不去的是準確初始化Pimpl結構成員的地方。選項是爲Private結構創建一個構造函數,並在那裏初始化它們,或者在主類的構造函數中初始化它們。在pimpl類中初始化默認值的最佳位置?

myclass.hpp:

class MyClass { 
public: 
    MyClass(); 
    ~MyClass(); 
private: 
    struct Private; unique_ptr<Private> p; 
}; 

myclass.cpp:

#include "myclass.hpp" 
#include <string> 

struct MyClass::Private { 
    int some_var; 
    std::string a_string; 

    // Option A 
    Private() : 
     some_var {42}, 
     a_string {"foo"} 
    {} 
}; 

MyClass::MyClass() : p(new MyClass::Private) { 
    // Option B 
    p->some_var = 42; 
    p->a_string = "foo"; 
} 

目前我實在不明白這兩個以外,如果我是,由於某種原因,之間的差異,以想要創建新的Private對象或將它們複製到某處,然後選擇A可能更可取。它還能夠初始化初始化列表中的變量,以確定其價值。但是,我發現選項B的可讀性更高,可維護性也更高。有沒有什麼東西我沒有看到哪一種可能會以某種方式傾斜秤?

+0

那麼,使用初始化列表的效率稍高一點,但它不會有太大的區別。只要做你發現更可讀的東西。 – 2012-04-02 20:00:58

+0

如果實現類是一個聚合,你可以說'p(new MyClass :: Impl {'a',1,true,{1,2,3}})''。 – 2012-04-02 20:03:20

回答

5

務必遵循RAII的方法,並在您的Private類型中初始化成員。如果你保留本地的東西(更重要的是,在合乎邏輯的地方),維護會感謝你。更重要的是,你將能夠有常量會員,如果你使用選項A.

如果你從你的MyClass構造函數傳遞值,那麼就創造一個合適的構造函數Private

struct MyClass::Private { 
    int const some_var; // const members work now 
    std::string a_string; 

    // Option C 
    Private(int const some_var, std::string const& a_string) : 
     some_var {some_var}, 
     a_string {a_string} 
    {} 
}; 

MyClass::MyClass() : p(new MyClass::Private(42,"foo")) { 
} 

否則你的Private成員將被默認構造,只是稍後被覆蓋(這與int s無關,但更復雜的類型呢?)。

+0

接受這個答案是因爲關於以下RAII方法的觀點,而且當我問我有沒有看到某些東西時,const成員就是我正在尋找的那些東西。乾杯。 – 2012-04-03 15:40:47

1

正如上面@Charles Salvia指出的那樣,任何兩個構造函數中的賦值都會產生一些開銷,因爲變量在賦值之前是默認構造的。這個開銷的數量當然很大程度上取決於你的變量的類型。

如果你能接受這一點,我認爲去最可讀的版本是最好的。所以,如果你在MyClass的構造函數中發現賦值最具可讀性,那就去做吧。

但是,考慮到初始化程序列表(對於Private c'tor)沒有辦法,即當您的成員變量沒有默認構造函數或者使用引用或常量時。

您可能希望從案例到案例中做出決定,但使用初始化程序列表的「始終」會使新增數據成員的事物保持一致和麪向未來。