一致定义C++;类成员作为唯一指针; 在C++中,常见的事情是:

一致定义C++;类成员作为唯一指针; 在C++中,常见的事情是:,c++,c++11,smart-pointers,C++,C++11,Smart Pointers,C类标题 //== C.h ==// #pragma once #include "B.h" class C { B b; }; B类标题 //== B.h ==// #pragma once #include "A.h" class B { A a; }; //== B.h ==// #pragma once #include <memory> // proto class A; class B { std::unique_ptr<A>

C类标题

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

class C
{
    B b;
};
B类标题

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

class B
{
    A a;
};
//== B.h ==//
#pragma once
#include <memory>

// proto
class A;

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

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

class A
{

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

class A
{

};
因为
C.h
包括
B.h
,而
B.h
包括
A.h
C.h
最终了解了
A.h
的实现细节。在这种情况下,标题仅包含三层,但在包含一个标题的大型项目中,可能会很快导致包含数百个附加标题。也会导致编译时间过长

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

C类标题:

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

// proto
class B;

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

我的问题是:

  • 用唯一的指针替换所有类成员(类和结构)是好的设计实践(好主意)吗?他们额外的优点还是缺点

如果直接数据成员的类型支持复制,则默认情况下直接数据成员支持复制。而且它的效率最高。如果你觉得把它用于更短的构建时间是值得的,那么为什么使用C++,为什么不使用java语言呢? 换句话说,这似乎是一个不好的想法


在使用C++时,对于较短的编译时间,考虑更快的机器或构建服务器Park。

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

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

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


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

这类似于pimpl习惯用法。一个缺点是,现在每次你想访问成员时都会有一个间接寻址,而且你的类布局现在在内存中被有效地分割了。pImpl将类拆分为私有部分和公共部分,并允许通过公共接口访问私有实现。它也是一个编译防火墙,但有些不同。这甚至不是一个格式良好的代码。如果完整类声明不存在,则无法将unique_ptr实例化为默认的deleter,因为它将调用转发类型上的delete,这是未定义的行为。我同意@Simple,你的建议只不过是Pimpl。unique\u ptr将在编译单元(cpp)内实例化,其中将包含相应的头。@galop1n你不需要完整的类型,否则就不可能使用
unique\u ptr
实现Pimpl。但是你需要一个析构函数声明。看见