【问题标题】:Consistently defining C++ class members as unique pointers;一致地将 C++ 类成员定义为唯一指针;
【发布时间】:2014-02-24 12:56:55
【问题描述】:

在 C++ 中,通常会看到以下内容:

C类头

//== C.h ==//
#pragma once
#include "B.h"

class C
{
    B b;
};

B 类的标题

//== B.h ==//
#pragma once
#include "A.h"

class B
{
    A a;
};

A类的头文件

//== A.h ==//
#pragma once

class A
{

};

因为C.h包含B.h,而B.h包含A.hC.h 最终了解了有关 A.h 的实现细节。在这种情况下,标题仅包含三层深度,但在大型项目中,包含一个标题会很快导致包含数百个额外的标题。也会导致编译时间过长。

在 C++ 11 中,我可以将标题声明如下:

C类的头文件:

//== C.h ==//
#pragma once
#include <memory>

// proto
class B;

class C
{
    std::unique_ptr<B> b;
};

B 类的标题

//== B.h ==//
#pragma once
#include <memory>

// proto
class A;

class B
{
    std::unique_ptr<A> a;
};

A类的头文件

//== A.h ==//
#pragma once

class A
{

};

当用智能指针替换所有成员(类、结构)时,我可以包含C.h,而不必知道类 B 的实现。现在每个 cpp 文件只需要知道它的成员,而不必知道它的成员的内存布局。

我的问题是:

  • 用唯一的指针替换所有类成员(无论是类还是结构)是一种好的设计实践(一个好主意)吗?他们的其他优点或缺点是什么?

【问题讨论】:

  • 这类似于 pimpl 成语。不利的一面是,现在每次您想要访问成员时都会进行间接处理,并且您的类布局现在有效地分散在内存中。
  • 不完全。 pImpl 将一个类拆分为私有和公共部分,并允许通过公共接口访问私有实现。它也是一个编译防火墙,但有些不同。
  • 这甚至不是一个格式良好的代码。如果完整的类声明不存在,则不能使用默认删除器实例化 unique_ptr,因为它会在转发类型上调用 delete,这是未定义的行为。我同意@Simple,你提出的不过是Pimpl。
  • unique_ptr 将在包含相应标头的编译单元 (cpp) 内实例化。
  • @galop1n 你不需要完整的类型,否则不可能使用unique_ptr 实现pimpl。但是你需要一个析构函数声明。见this related question

标签: c++ c++11 smart-pointers


【解决方案1】:

直接直接数据成员默认支持复制,如果它们的类型支持复制的话。而且效率最高。如果有人觉得用它来换取更短的构建时间是值得的,那么为什么要使用 C++,为什么不(然后)只使用一种最大限度地利用这种权衡的语言,例如 Java 或 C#。

换句话说,这似乎不是个好主意。

若要在仍使用 C++ 的同时缩短构建时间,请考虑使用更快的机器或构建服务器园区。

【讨论】:

    【解决方案2】:

    用指针替换所有成员不是一个好主意,因为它会增加额外的取消引用层。直接成员实际上是在包含对象中分配的,因此访问它只需要与包含对象的位置有一个固定的偏移量。

    如果将所有内容隐藏在指针后面,则需要访问指针成员,然后取消引用指针以访问数据(将在内存中的其他位置)。就个人而言,这只是微不足道的开销,但如果将这一原则扩展到整个程序,它很快就会加起来。

    另一个需要牢记的问题是可维护性。如果您通过指针存储所有内容,那么您需要手动包括适当的构造和复制。这可能会导致大型项目出现各种问题,因为它增加了程序员出错的可能性。相比之下,如果您使用直接成员,编译器会自动执行很多操作。

    另一个值得研究的替代方案是 PIMPL 设计模式(私有实现,或指向实现的指针)。它本质上是一种将类的私有细节隐藏在其源文件中的方法,以减少头文件的依赖关系。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-12
      • 2018-02-25
      • 1970-01-01
      • 2015-01-24
      • 2016-10-10
      • 2020-06-24
      • 1970-01-01
      相关资源
      最近更新 更多