我一直在浏览Andrei Alexandrescu撰写的现代C ++设计书,这看起来很有趣。然而,它非常广泛地使用模板,我想知道如果因为尺寸考虑使用C ++进行移动平台开发(Brew MP,WebOS,iOS等),是否应该避免这种情况。
在Symbian OS C ++中,不鼓励标准使用模板,Symbian操作系统本身使用它们,但使用称为精简模板的习惯用法,其中底层实现以C风格完成,使用带有薄模板的void *指针。这样可以达到类型安全。 他们使用这个习惯用语而不是经常使用模板的原因是为了避免代码膨胀。
那么在为移动平台开发应用程序时,有关使用模板的意见(或事实)是什么。
答案 0 :(得分:9)
继续使用模板,只要它们使代码更易于理解和维护。在移动平台上避免使用模板可归类为“过早优化”。
如果遇到可执行文件大小的问题,请在必要时重新设计,但不要假设模板在遇到任何实际问题之前会导致问题。
“现代C ++设计”中的很多内容和类似的书籍都不会导致代码膨胀,因为它的大部分内容都是为了确保类型安全并进行编译时的元编程魔术,而不是生成代码。
模板可用于执行许多不同的操作。它们可以生成比您预期更多的代码,但这并不是禁止使用它们的理由。不久之前,由于担心代码大小和性能,各个权威机构建议避免异常,虚函数,浮点数学甚至类,但是人们做了这些事情,并且不知何故一切都很好。
答案 1 :(得分:5)
模板不一定会导致代码膨胀。如果您编写一个函数或类模板并将其实例化为十几个不同的类型,那么是的,您会得到很多重复的代码(可能,无论如何。有些编译器可以将相同的实例重新合并在一起)。
但是,如果仅为一种类型实例化模板,则代码大小中存在零成本。如果你实例化它几次,你支付一定的费用,但如果你用其他任何方法来实现同样的事情,你也最终会付钱。动态多态(虚函数和继承)也不是免费的。你需要为vtable付费,生成代码以方便所有类型转换和必要的转换,并且仅仅因为代码无法内联或优化。
以std::vector
为例,是的,如果同时使用vector<int>
和vector<float>
,则会获得两份部分代码的副本。但是使用模板,只会编译实际使用的代码。您从未调用过的成员函数不会生成任何代码,即使在 编译的函数中,编译器也可以消除大量代码。例如,对于某些类型,异常处理代码可能是不必要的,因此编译器可以消除它,产生较小的代码,而不是使用动态多态,而编译器将无法生成关于所存储类型的任何假设。因此,在这个组成的示例中,您将获得为vector<int>
和vector<float>
生成的一些代码,但每个代码都会比多态小很多例如,您可能会在Java中找到矢量。
使用模板的主要问题是它需要一个支持它的编译器。在PC上,这没问题。在任何其他具有成熟C ++编译器的平台上,都没问题。
但并非所有平台都有现代化的重型C ++编译器。有些不支持许多高级功能,有些功能只是不足以使模板代码工作所需的优化(例如,模板往往需要很多内联)。所以在某些平台上,最好避免使用模板。不是因为对代码大小的任何担心,而是因为编译器可能无法处理它。
答案 2 :(得分:2)
无论你做什么,都不要尝试编写一些代码,编译它们,并比较可执行文件大小或代码重复。
答案 3 :(得分:1)
我会说这个建议一般(不仅仅与移动开发有关)。现代C ++设计中描述的一些技术可能会导致构建时间过长和代码膨胀。
在处理像手机这样的“模糊”设备时尤其如此。许多模板技术依赖于编译器和链接器在消除未使用/重复代码方面做得很好。如果他们不这样做,您可能会在代码中散布数百个重复std::vector
个实例。相信我,我已经看到了这种情况。
这并不是说现代C ++设计是一本坏书,或者说模板很糟糕。但特别是在嵌入式项目中,最好注意,因为它可以咬人。
答案 4 :(得分:1)
根据我个人使用(甚至滥用)模板的经验,很少会导致大量代码膨胀,使用-Os
进行编译会有很大帮助。
多次看到大型模板类重复(实例化)并不常见,因为很少类是 huge ,并且因为在大多数情况下,您只使用几个不同的参数实例化模板,而不是数百个。除了可以很容易地在最大的模板类/函数中重用一些常用代码,编译器将帮助您完成此任务。
通常,数据(图形,音频......)的大小比代码大几个数量级。所以我不担心。
当然,我说的可能有例外,但我猜他们主要是关于高级(特殊 / 怪异 / 复杂的)东西,而不是最常见的日常课程。
总结我的建议:尽可能多地使用模板,如果出现问题,您可以通过分析找到它,并且您可以轻松地优化尺寸。