1

我对 PImpl 进行了相当广泛的使用,而我发现自己正在纠结的事情是在哪里初始化 Pimpl 结构的成员。选项是为Private结构创建一个构造函数并在那里初始化它们,或者在主类的构造函数中初始化它们。

myclass.hpp:

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

我的类.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 往往更具可读性,也许也更易于维护。这里有什么我看不到的东西可能会以一种或另一种方式倾斜天平吗?

4

2 回答 2

5

无论如何,请遵循 RAII 方法并在您的Private类型中初始化成员。如果您将内容保存在本地(更重要的是,在合乎逻辑的地方),维护将感谢您。更重要的是,如果您使用选项 A,您将能够拥有 const 成员。

如果你必须从你的MyClassctor传递值,那么请创建一个适当的构造函数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成员将被默认构造,只是稍后被覆盖(这与ints 无关,但是更复杂的类型呢?)。

于 2012-04-02T20:13:39.337 回答
1

正如上面@Charles Salvia 已经指出的那样,两个构造函数中的任何一个中的赋值都会产生一些开销,因为变量是在赋值之前默认构造的。当然,这种开销的大小很大程度上取决于变量的类型。

如果你能接受这一点,我认为选择最易读的版本是最好的。因此,如果您发现MyClass' 的构造函数中的赋值最易读,那就去做吧。

但是,请考虑到初始化器列表(对于Privatec'tor)没有办法,即当您的成员变量没有默认构造函数或当您使用引用或常量时。

您可能希望根据具体情况来决定这一点,但“始终”使用初始化列表将使新添加的数据成员保持一致和面向未来。

于 2012-04-02T20:22:27.800 回答