重用对象与创建新对象
Reuse object vs. creating new object
我们的一个项目处理大量数据。它从数据库中选择数据,并将结果序列化为 JSON/XML。
有时,所选行的数量可以轻松达到 5000 万大关。
然而,该程序的运行时一开始很糟糕。
因此,我们通过一项重大调整重构了程序:
不会为每一行重新创建序列化的工作对象,而是清除并重新初始化该对象。
例如:
以前:
对于每个数据库行,我们创建一个 DatabaseRowSerializer 的对象并调用特定的序列化函数。
// Loop with all dbRows
{
DatabaseRowSerializer serializer(dbRow);
result.add(serializer.toXml());
}
后:
DatabaseRowSerializer 的构造函数不设置 dbRow。相反,这将由 initDbRow((-函数完成。
这里最主要的是,整个运行时只会使用一个对象。在 dbRow 的序列化之后,clear((-函数 将调用以重置对象。
DatabaseRowSerializer serializer;
// Loop with all dbRows
{
serializier.initDbRow(dbRow);
result.add(serializer.toXml());
serializier.clear();
}
所以我的问题:
这真的是解决问题的好方法吗? 在我看来,init((-函数并不是很聪明。通常应该使用构造函数来初始化可能的参数。
您通常更喜欢哪种方式?之前还是之后?
一方面,这是主观的。另一方面,意见广泛同意,在C++中你应该避免这种"init function"成语,因为:
-
这是更糟糕的代码
- 你必须记住"初始化"你的对象,如果你不这样做,它处于什么状态?对象不应处于"死"状态。(不要让我从"移动"对象开始...这就是为什么C++引入构造函数和析构函数的原因,因为旧的 C 方法是一种混合,生成的程序更难证明是正确的。
-
这是不必要的
-
每次创建
DatabaseRowSerializer
基本上没有开销,除非它的构造函数比你的initDbRow
函数做得更多,在这种情况下,你的两个示例无论如何都不等效。即使编译器没有优化不必要的"分配",无论如何也没有真正的分配,因为对象只是占用堆栈上的空间,无论如何它都必须这样做。
因此,如果此更改确实解决了您的性能问题,那么可能还有其他事情发生。
-
使用构造函数和析构函数。自由而自豪!
这是写C++时的常见建议。
如果出于任何原因确实希望使序列化程序可重用,则可能的第三种方法是将其所有状态移动到实际的操作函数调用中:
DatabaseRowSerializer serializer;
// loop with all dbRows
{
result.add(serializer.toXml(dbRow));
}
如果序列化程序希望缓存信息或重用动态分配的缓冲区以帮助提高性能,则可以执行此操作。这当然会向序列化程序添加一些状态。
如果你这样做并且仍然没有任何状态,那么整个事情可能只是一个静态调用:
// loop with all dbRows
{
result.add(DatabaseRowSerializer::toXml(dbRow));
}
...但它也可能只是一个函数。
最终,我们无法确切知道什么最适合您,但有很多选择和考虑因素。
总的来说,我同意LRiO在另一个答案中提出的观点。
只是将构造函数移出循环并不是一个好主意。
但是,对于这种类型的循环体:
- 馈送对象一些数据
- 转换对象内的数据
- 从对象返回转换后的数据
恕我直言,通常情况下,转换对象将分配一些缓冲区(在堆上(,当使用带有 init 函数的第二个表单时,这些缓冲区可能会被重用。在朴素的实现中,这种重用甚至可能不是故意的,只是实现的副作用。
因此,您看到重构(将对象构造函数提升到循环之外(加快了速度,这可能是因为对象现在能够重用某些缓冲区并避免这些缓冲区的重复"冗余"堆分配。
所以,总结一下:
您不希望构造函数本身就被吊出循环。但是,您希望在循环迭代中保留所有可以保留的缓冲区。
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- C++ 如何在将新对象分配给另一个对象时创建新对象
- 重用对象与创建新对象
- C++,创建新对象时类的对象更改
- 运算符重载 += 添加新对象
- 如何在运行时在对象数组中动态追加新对象C++并打印它们
- 从使用概念定义的函数返回新对象
- 从 Rcpp 函数返回指向"新"对象的指针的正确方法
- 如何删除派生类中基类对象的新对象
- 有没有一种方法可以从函数中返回一个新对象或对现有对象的引用
- 为模板参数类型中的新对象分配内存
- 删除通过取消引用新对象初始化的对象
- C++ 实例化新对象时不接受继承方法默认参数值
- 有没有办法删除传递给函数"foo(新对象())"的对象?
- 将 Eigen::MatrixXd 转换为 arma::mat 并在新对象上制作副本
- 创建新对象并立即为其设置属性时出现编译器错误
- 如何异步销毁对象并立即分配一个新对象
- 删除传递给 C++ 中成员函数的新对象
- 具有构造函数的新对象数组,需要在C++中设置参数
- 我可以制作一个对象方法,如果单独调用,它将自行修改,但如果在复制初始化期间调用,则会返回一个新对象?