在pimpl类中初始化默认值的最佳位置?

时间:2012-04-02 19:58:21

标签: c++ pimpl-idiom

我非常广泛地使用了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往往更具可读性,也许更易于维护。在这里我有什么东西我没看到哪种可能会使这种或那种方式倾斜?

2 个答案:

答案 0 :(得分:5)

无论如何,请遵循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无关,但更复杂的类型呢?)。

答案 1 :(得分:1)

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

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

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

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