标签: pimpl

pimpl 成语是否比始终使用 unique_ptr 作为成员变量更好?

在我的工作场所,我们有这样的约定:几乎每个类(除了极少数例外)都使用unique_ptrs、原始指针或引用作为成员变量来实现。

这是因为编译时间的原因:通过这种方式,您只需要在头文件中对类进行前向声明,并且只需要在 cpp 中包含该文件。此外,如果您更改包含的类的 .h 或 .cpp,unique_ptr则不需要重新编译。

我认为这种模式至少有以下缺点:

  • 它迫使您编写自己的复制构造函数和赋值运算符,并且您必须单独管理每个变量,如果您想保持复制的语义。
  • 代码的语法变得非常繁琐,例如您将拥有std::vector<std::unique_ptr<MyClass>>而不是更简单的std::vector<MyPimplClass>.
  • 指针的常量性不会传播到指向的对象,除非你使用 std::experimental::propagate_const,我不能使用它。

因此,我想到建议对作为指针包含的类使用 pImpl 习惯用法,而不是在任何地方使用指针。通过这种方式,我认为我们可以两全其美:

  • 更快的编译时间:pimpl 减少编译依赖
  • 要编写复制构造函数和复制赋值运算符,您只需执行以下操作:
A::A(const A& rhs) : pImpl(std::make_unique<Impl>(*rhs.pImpl)) {}
A& A::operator=(const A& rhs) {
  *pImpl = *rhs.pImpl;
  return *this;
}
Run Code Online (Sandbox Code Playgroud)
  • 常量被传播到成员对象。

在这一点上,我与我的同事进行了讨论,他们认为 pImpl 并不比在任何地方使用指针更好,原因如下:

  • 与使用指针相比,它减少了编译依赖性,因为如果您使用 pImpl,则在更改公共接口时必须重新编译包含 pImpl 类的类:如果您只使用指针而不是 pImpl 类,则不需要即使在更改头文件时也要重新编译。

现在我有点困惑。我认为我们的实际约定并不比 pImpl 好,但我无法争论为什么。

所以我有一些问题:

  • 在这种情况下, pImpl 成语是一个很好的选择吗?
  • 除了我提到的那些之外,我们正在使用的模式还有其他缺点吗?

编辑:我正在添加一些示例来阐明这两种方法。

  • 随着接近unique_ptr为成员:
// B.h
#pragma once
class B {
    int i = 42;
public:
    void print();
}; …
Run Code Online (Sandbox Code Playgroud)

c++ compile-time pimpl

9
推荐指数
1
解决办法
160
查看次数

为什么在 PIMPL 中不能访问实现类的常量函数?

我想在 C++ 中尝试使用 PIMPL。

就我而言,我正在使用operator()访问私人成员。

接口类A和实现类AImpl都有operator() constoperator()

代码如下所示:

#include <iostream>
class AImpl
{
public:
    explicit AImpl()
    {
        x = 0;
    }
    const int &operator()() const
    {
        std::cout << "const access in AImpl" << std::endl;
        return x;
    }
    int &operator()()
    {
        std::cout << "not const access in AImpl" << std::endl;
        return x;
    }

private:
    int x;
};

class A
{
public:
    A()
    {
        impl = new AImpl;
    }
    ~A()
    {
        delete …
Run Code Online (Sandbox Code Playgroud)

c++ constants pimpl

2
推荐指数
1
解决办法
82
查看次数

标签 统计

c++ ×2

pimpl ×2

compile-time ×1

constants ×1