“价格”是多少?在带有 C++ 的嵌入式环境中使用继承?
我正在使用 C++ 开始一个新的嵌入式项目,我想知道使用面向接口的设计是否太昂贵。像这样的东西:
typedef int data;
class data_provider {
public:
virtual data get_data() = 0;
};
class specific_data_provider : public data_provider {
public:
data get_data() {
return 7;
}
};
class my_device {
public:
data_provider * dp;
data d;
my_device (data_provider * adp) {
dp = adp;
d = 0;
}
void update() {
d = dp->get_data();
}
};
int
main() {
specific_data_provider sdp;
my_device dev(&sdp);
dev.update();
printf("d = %d\n", dev.d);
return 0;
}
I'm starting a new embedded project with C++ and I was wondering if it is too much expensive to use a interface oriented design. Something like this:
typedef int data;
class data_provider {
public:
virtual data get_data() = 0;
};
class specific_data_provider : public data_provider {
public:
data get_data() {
return 7;
}
};
class my_device {
public:
data_provider * dp;
data d;
my_device (data_provider * adp) {
dp = adp;
d = 0;
}
void update() {
d = dp->get_data();
}
};
int
main() {
specific_data_provider sdp;
my_device dev(&sdp);
dev.update();
printf("d = %d\n", dev.d);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
继承本身是免费的。例如,如下所示,从性能/内存的角度来看,
B
和C
是相同的:只有当您拥有虚拟函数时,继承才会产生成本。
在这里,在几乎所有实现中,由于虚拟函数的原因,
A
和B
的指针大小都会大一个。虚函数还具有其他缺点(与非虚函数相比)
如果您使用多重继承,那么事情会变得更糟。
通常人们会告诉您“在分析器告诉您之前不要担心性能”,但如果性能对您来说非常重要,那么这是一个糟糕的建议。如果您不担心性能,那么最终会出现到处都是虚拟函数的情况,并且当您运行探查器时,没有一个热点需要优化——整个代码库都需要优化。
我的建议是,如果性能对您很重要,则进行设计。如果可能的话,设计时应避免使用虚拟函数。围绕缓存设计数据:更喜欢数组而不是基于节点的数据结构,例如
std::list
和std::map
。即使您有一个包含数千个元素的容器,并且经常在中间插入,我仍然会在某些架构上选择数组。复制插入数据时丢失的数千个周期很可能会被每次遍历时实现的缓存局部性所抵消(还记得单个 L2 缓存未命中的成本吗?您可以预期其中很多当遍历链表时)Inheritance, on its own, is free. For example, below,
B
andC
are the same from a performance/memory point of view:Inheritance only incurs a cost when you have virtual functions.
Here, on virtually all implementations, both
A
andB
will be one pointer size larger due to the virtual function.Virtual functions also have other drawbacks (when compared with non-virtual functions)
If you use multiple inheritance then things get worse.
Often people will tell you "don't worry about performance until your profiler tells you to", but this is terrible advice if performance is at all important to you. If you don't worry about performance then what happens is that you end up with virtual functions everywhere, and when you run the profiler, there is no one hotspot that needs optimising -- the whole code base needs optimising.
My advice would be to design for performance if it is important to you. Design to avoid the need for virtual functions if at all possible. Design your data around the cache: prefer arrays to node-based data structures like
std::list
andstd::map
. Even if you have a container of a few thousand elements with frequent insertions into the middle, I would still go for an array on certain architectures. The several thousand cycles you lose copying data for the insertions may well be offset by the cache locality you will achieve on each traversal (Remember the cost of a single L2 cache miss? You can expect a lot of those when traversing a linked list)继承基本上是免费的。然而,多态性和动态分派(
虚拟
)会带来一些后果:具有虚拟方法的类的每个实例都包含一个指向vtable
的指针,该指针用于选择正确的方法。方法来调用。这为每个虚拟方法调用增加了两次内存访问。在大多数情况下,这不会成为问题,但它可能成为某些实时应用程序的瓶颈。
Inheritance is basically free. However, polymorphism and dynamic dispatch (
virtual
) have some consequences: each instance of a class with a virtual method contains a pointer to thevtable
, which is used to select the right method to call. This adds two memory access for each virtual method call.In most cases it won't be a problem, but it can become a bottleneck in some real time applications.
确实取决于您的硬件。继承本身可能不会花费您任何费用。虚拟方法会为每个类中的 vTable 消耗一定量的内存。打开异常处理可能会消耗更多的内存和性能。我在 NetBurner 平台上广泛使用了 C++ 的所有功能,其中包括 MOD5272 等芯片,该芯片具有几兆闪存和 8 兆 RAM。另外,有些事情可能与实现相关,取决于我使用的 GCC 工具链,当使用 cout 而不是 printf 时,您会占用大量内存(它似乎链接到一堆库)。您可能对我撰写的关于成本的博客文章感兴趣类型安全代码。您必须在您的环境中运行类似的测试才能真正回答您的问题。
Really depends on your hardware. Inheritance per se probably doesn't cost you anything. Virtual methods cost you some amount of memory for the vTable in each class. Turning on exception handling probably costs you even more in both memory and performance. I have used all the features of C++ extensively on the NetBurner platform with chips like the MOD5272 which have a couple of Megs of Flash and 8 Megs of RAM. Also some things may be implementation dependent, on the GCC toolchain I use, when cout gets used instead of printf you take a big memory hit (it appears to link in a bunch of libraries). You might be interested in a blog post I wrote on the cost of type safe code. You would have to run similar tests on your environment to truly answer your question.
通常的建议是使代码清晰和正确,然后只有在实践中证明是一个问题(太慢或内存太多)时才考虑优化。
The usual advice is to make the code clear and correct, and then think about optimisations only if it proves to be a problem (too slow or too much memory) in practice.