[英]Is pimpl idiom better than using always unique_ptr as member variables?
在我的工作场所,我们有这样的约定:几乎每个 class(除了极少数例外)都使用unique_ptr
、原始指针或引用作为成员变量来实现。
这是因为编译时间的原因:通过这种方式,您只需要在 header 文件中为 class 进行前向声明,并且只需将该文件包含在您的 cpp 中。 此外,如果您更改包含在unique_ptr
中的 class 的.h 或 .cpp,则无需重新编译。
我认为这种模式至少有以下缺点:
std::vector<std::unique_ptr<MyClass>>
而不是更简单的std::vector<MyPimplClass>
。所以我想到建议使用 pImpl 习惯用法作为指针包含的类,而不是在任何地方都使用指针。 通过这种方式,我认为我们可以两全其美:
A::A(const A& rhs) : pImpl(std::make_unique<Impl>(*rhs.pImpl)) {}
A& A::operator=(const A& rhs) {
*pImpl = *rhs.pImpl;
return *this;
}
在这一点上,我与我的同事进行了讨论,他们认为 pImpl 并不比在任何地方使用指针更好,原因如下:
现在我有点困惑。 我认为我们的实际约定并不比 pImpl 更好,但我无法解释为什么。
所以我有一些问题:
编辑:我正在添加一些示例来阐明这两种方法。
unique_ptr
作为成员的方法:// B.h
#pragma once
class B {
int i = 42;
public:
void print();
};
// B.cpp
#include "B.h"
#include <iostream>
void B::print() { std::cout << i << '\n'; }
// A.h
#pragma once
#include <memory>
class B;
class A {
std::unique_ptr<B> b;
public:
A();
~A();
void printB();
};
// A.cpp
#include "A.h"
#include "B.h"
A::A() : b{ std::make_unique<B>() } {}
A::~A() = default;
void A::printB() { b->print(); }
// Bp.h
#pragma once
#include <memory>
class Bp {
struct Impl;
std::unique_ptr<Impl> m_pImpl;
public:
Bp();
~Bp();
void print();
};
// Bp.cpp
#include "Bp.h"
#include <iostream>
struct Bp::Impl {
int i = 42;
};
Bp::Bp() : m_pImpl{ std::make_unique<Impl>() } {}
Bp::~Bp() = default;
void Bp::print() { std::cout << m_pImpl->i << '\n'; }
// Ap.h
#pragma once
#include <memory>
#include "Bp.h"
class Ap {
Bp b;
public:
void printB();
};
// Ap.cpp
#include "Ap.h"
#include "Bp.h"
void Ap::printB() { b.print(); }
主要的:
// main.cpp
#include "Ap.h"
#include "A.h"
int main(int argc, char** argv) {
A a{};
a.printB();
Ap aPimpl{};
aPimpl.printB();
}
此外,当我说第一种方法我们不需要重新编译时,我想更加准确,这是不准确的。 的确,我们需要重新编译更少的文件:
过了一段时间,我对这个问题有了更广泛的理解,终于可以回答我自己的问题了。
事实证明,我所说的并不完全正确。
实际上在下面的代码中只有Bp
class 是 pImpl。 如果我们把Ap
也改成 pImpl 我们就得到了,如果我们改变 Bp.h 我们只需要重新编译 Ap.cpp、Bp.cpp,这与具有unique_ptr
s 的相应解决方案相同。
话虽如此,我想我可以说 pImpl 的解决方案通常看起来比unique_ptr
的解决方案更好(我们只需要 pImpl 正确的类。)。
出于这个原因,我们决定切换到 pImpl idiom 作为我们类的默认设置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.