在皮条类中初始化默认值的最佳位置

Best place to initialize default values in a pimpl class?

本文关键字:默认值 最佳位置 初始化      更新时间:2023-10-16

我非常广泛地使用了PImpl,我发现自己一直在思考如何初始化PImpl结构的成员。选项是为Private结构创建一个构造函数并在那里初始化它们,或者在主类的构造函数中初始化它们。

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

无论如何,遵循RAII方法并在Private类型中初始化成员。如果你把东西放在本地(更重要的是,放在合乎逻辑的地方),维护人员会感谢你的。更重要的是,如果你使用选项A.,你将能够拥有const成员

如果必须从MyClass ctor传递值,请为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无关,但更复杂的类型呢?)。

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

如果你能接受这一点,我认为选择可读性最强的版本是最好的。所以,如果你发现MyClass的构造函数中的赋值是最可读的,那就去做吧

但是,请注意,没有办法绕过初始值设定项列表(对于Private c'tor),即当您的成员变量没有默认构造函数时,或者当您使用引用或常量时。

您可能想根据具体情况来决定,但"始终"使用初始值设定项列表将使新添加的数据成员保持一致并经得起将来的考验。