我在一个项目中广泛使用了shared_ptr和STL,这导致了像shared_ptr< vector< shared_ptr<const Foo> > >
那样过时,容易出错的类型(我喜欢ObjC程序员,长名称是常态但是这太过分了。)我相信,我会更加清楚地一致地调用这个FooListPtr
并记录命名约定,“Ptr”表示shared_ptr,“List”表示shared_ptr的向量。
这很容易使用typedef,但它会导致标题出现问题。我似乎有几个选项来定义FooListPtr
:
这里有最佳做法吗?当可重用性,可读性和一致性至关重要时,它们如何在实际代码中生效?
如果其他人想要添加其他选项供讨论,我已经标记了这个社区维基。
答案 0 :(得分:13)
我正在编写一个听起来像是使用common.h
方法的项目。它对该项目非常有效。
有一个名为ForwardsDecl.h
的文件位于预编译的头文件中,只是向前声明所有重要的类和必要的typedef。在这种情况下,使用unique_ptr
代替shared_ptr
,但用法应该类似。它看起来像这样:
// Forward declarations
class ObjectA;
class ObjectB;
class ObjectC;
// List typedefs
typedef std::vector<std::unique_ptr<ObjectA>> ObjectAList;
typedef std::vector<std::unique_ptr<ObjectB>> ObjectBList;
typedef std::vector<std::unique_ptr<ObjectC>> ObjectCList;
此代码被Visual C ++ 2010接受,即使这些类仅是前向声明的(完整的类定义不是必需的,因此不需要包含每个类的头文件)。我不知道那个标准和其他编译器是否需要完整的类定义,但它不是很有用:另一个类(ObjectD)可以将ObjectAList作为成员,而不需要包含ObjectA.h - 这可以真的有助于减少头文件依赖!
维护不是特别的问题,因为转发声明只需要写一次,任何后续更改只需要在类的头文件中的完整声明中发生(这将触发更少的源文件重新编译)由于减少了依赖性。)
最后看起来这可以在项目之间共享(我没有尝试过),因为即使项目实际上没有声明ObjectA,也没关系,因为它只是前向声明的,如果你不使用它编译器不关心。因此,该文件可以包含其所使用的所有项目中的类的名称,并且如果特定项目缺少某些项,则无关紧要。所需要的只是必要的完整声明标题(例如ObjectA.h
)包含在实际使用它们的任何源(。cpp)文件中。
答案 1 :(得分:6)
我会使用前向标头和一种common.h
标头的组合方法,该标头特定于您的项目,并且只包含所有前向声明标头以及任何其他常见且轻量级的内容。
您抱怨保持两次标头数量的开销,但我不认为这应该是一个太大的问题:转发标头通常只需要知道非常有限数量的类型(一个?),并且有时甚至不是完整的类型。
你甚至可以尝试使用脚本自动生成标题(例如在SeqAn中完成),如果有真的那么多标题。
答案 2 :(得分:4)
+1用于记录typedef约定。
所以这里有一些初步建议(从其他问题修改过来......)
标准类型标题<boost/shared_ptr.hpp>
,<vector>
等可以进入项目的预编译标题/共享包含文件。 这还不错。(我个人仍然会在需要的地方加入它们,但除了将它们放入PCH之外,还可以使用它们。)
如果容器是实现细节,则typedef将转到声明容器的位置(例如,如果容器是私有类成员,则为私有类成员)
关联类型(如FooListPtr
)转到Foo声明的位置,如果关联类型是该类型的主要用途。某些类型几乎总是如此 - 例如shared_ptr
。
如果Foo
获得一个单独的前向声明标题,并且关联类型没有问题,它也会移动到FooFwd.h。
如果类型仅与特定界面相关联(例如公共方法的参数),那么它就会出现。
如果共享类型(并且不符合以前的任何条件),它将获得自己的标头。请注意,这也意味着引入所有依赖项。
对我来说感觉“显而易见”,但我同意它作为编码标准并不好。
答案 3 :(得分:2)
答案 4 :(得分:1)
不幸的是,对于typedef,您必须在头文件的不理想选项之间进行选择。有一些特殊情况,其中选项一(在类标题中右侧)运行良好,但听起来它不适合您。在某些情况下,最后一个选项也可以正常工作,但通常情况下,您使用子类替换涉及具有std :: vector类型的单个成员的类的模式。根据您的情况,我将使用前向声明标头解决方案。有额外的打字和开销,但不会是C ++,对吧?它使事物分离,清洁和快速。