C++ 重用对象与创建新对象
我们的一个项目处理大量数据。它从数据库中选择数据,并将结果序列化为JSON/XML 有时,所选行的数量很容易达到5000万大关 然而,程序的运行时间在一开始就很糟糕 因此,我们对程序进行了一次重大调整: 序列化的工作对象不会为每一行重新创建,而是将清除并重新初始化该对象 例如: 之前: 对于每个数据库行,我们创建DatabaseRowSerializer的一个对象,并调用特定的serialize函数C++ 重用对象与创建新对象,c++,C++,我们的一个项目处理大量数据。它从数据库中选择数据,并将结果序列化为JSON/XML 有时,所选行的数量很容易达到5000万大关 然而,程序的运行时间在一开始就很糟糕 因此,我们对程序进行了一次重大调整: 序列化的工作对象不会为每一行重新创建,而是将清除并重新初始化该对象 例如: 之前: 对于每个数据库行,我们创建DatabaseRowSerializer的一个对象,并调用特定的serialize函数 // Loop with all dbRows { DatabaseRowSeriali
// Loop with all dbRows
{
DatabaseRowSerializer serializer(dbRow);
result.add(serializer.toXml());
}
之后:
DatabaseRowSerializer的构造函数未设置dbRow。相反,这将由initDbRow()函数完成
// Loop with all dbRows
{
DatabaseRowSerializer serializer(dbRow);
result.add(serializer.toXml());
}
这里的主要问题是,整个运行时只使用一个对象。在对dbRow进行序列化之后,clear()函数
将调用以重置对象
DatabaseRowSerializer serializer;
// Loop with all dbRows
{
serializier.initDbRow(dbRow);
result.add(serializer.toXml());
serializier.clear();
}
因此,我的问题是:
这真的是处理问题的好方法吗?
在我看来,init()函数并不是很聪明。通常,应该使用构造函数初始化可能的参数
你通常喜欢哪种方式?一方面,这是主观的。另一方面,舆论普遍认为C++中应该避免这种“init函数”的习惯用法:
- 你必须记住“初始化”你的对象,如果你没有,它处于什么状态?您的对象永远不应该处于“死”状态。(不要让我开始从“对象”……)这就是为什么C++引入构造函数和析构函数,因为旧的C方法有点混乱,结果程序更难证明正确。
- 每次创建
基本上没有开销,除非它的构造函数所做的工作超过了DatabaseRowSerializer
函数,在这种情况下,您的两个示例并不等价 即使您的编译器没有优化掉不必要的“分配”,也不会有真正的分配,因为对象只会占用堆栈上的空间,而且无论如何它都必须这样做 所以,如果这一改变真的解决了您的性能问题,那么可能还有其他问题initDbRow
如果您确实希望序列化程序因任何原因可重用,第三种可能的方法是将其所有状态移动到实际的操作函数调用中:
DatabaseRowSerializer serializer;
// loop with all dbRows
{
result.add(serializer.toXml(dbRow));
}
如果serialiser希望缓存信息或重用动态分配的缓冲区以提高性能,则可以这样做。这当然会给序列化程序添加一些状态
如果您这样做了,但仍然没有任何状态,那么整个过程可能只是一个静态调用:
// loop with all dbRows
{
result.add(DatabaseRowSerializer::toXml(dbRow));
}
…但它也可能只是一个函数
// Loop with all dbRows
{
DatabaseRowSerializer serializer(dbRow);
result.add(serializer.toXml());
}
最终,我们无法确切知道什么对您最有利,但有很多选择和考虑。大体上,我同意LRiO在报告中提出的观点 仅仅将构造函数移出循环不是一个好主意 但是对于这种样式的环体:
您不希望构造函数因为自身的原因而被吊出循环。但是您希望在循环迭代中保留所有可以保留的缓冲区。此“主要”更改是否解决了性能问题?否则,一般来说,C++的方式是RAII,即“不<代码>”(< /代码> /<代码>())/代码>,除非你解决一个比维护好的架构更重要的问题。我投票以基于意见的方式结束这个问题。@DevSolar关于这个问题,我们可以说很多客观的东西。这并不完全是“你最喜欢的编译器是什么?”用户2622344应该进行测试并从测试中得到答案。其他人可能会从他们的观点或原则中有所不同。在极少数情况下,可能值得尝试使用一个对象根据某些输入重复作业。您可以将类设计为从输入getWantedValue()构造对象。或者可以构造空对象getWantedValue(inputvalue)。在这种情况下,序列化程序可以是静态的,因为它没有任何状态。正确吗?@user2622344正确。因此,实际上,
DatabaseRowSerializer::toXml(dbRow)
可能是第四种有效的方法。什么对你最好取决于我们从这里看不到、知道或测量不到的东西。这是一个很好的观点。从“重复使用”设计开始,允许缓存和缓冲区重复使用以及其他优化,否则您将无法在以后添加这些优化。好吧,除非你再次重构:)