2

我有以下变量(简化情况):

std::array<std::array<float, 4>, 4> matrix;

我需要从程序中的函数返回这个变量。我可以使用std::unique_ptr或将其作为值返回(自动与动态内存)

由于我平台上浮点数的大小为 4 个字节,并且有 16 个位置,因此大小为16 * 4 = 64字节。

没有自定义分配器等的动态内存除了通常很慢之外还会导致内存碎片,所以我想知道作为自动内存与动态内存传递数据的实际限制可能是什么?我应该开始使用什么大小的动态内存?这个问题无法回答吗?

4

5 回答 5

2

如果您担心由于 init 函数返回这样的结构的大小,那么我不会(对该声明的警告(如果您不确定,您可以随时测量))。

所有现代编译器都已经在进行 RVO 和 NRVO 优化。因此,即使您按值返回,也不会制作副本。编译器已经计算出结果将发送到特定的目的地,并删除了副本并在目的地构建它。

因此,尺寸限制并不是真正的问题。

同样在 C++11 中引入了移动语义的概念。所以你不需要按值返回,而是通过移动返回。在大多数 std 容器中,这仅意味着交换几个指针(不幸的是,这对 std::array 没有帮助),但在一般情况下它运行良好。

所以对我来说,这可能是价值回报。尽管我可以将该结构包装在一个类中。这样一来,如果现实很糟糕并且确实花费了很多,我可以在内部更改类以进行补偿,而无需更改代码。

于 2012-10-22T20:40:54.920 回答
0

我认为分配 64 字节不会导致任何碎片。根据我在 32 位环境中使用大型应用程序的经验,大于 16 MB 的分配可能会由于碎片问题而失败。对于导致碎片的分配,它们应该存在很长时间。对于服务器代码,这超过了几天。在 64 位环境中,碎片不太可能发生。

按值传递参数意味着创建一个副本。这可能效率不高。推荐的解决方法是使用引用。大小没有众所周知的限制。

根据我的经验,我会为 PC 等平台推荐以下内容:

  • 变量的大小小于 100 字节 - 按值传递;
  • var 的大小大于 1 KB - 使用引用并避免复制;

中间的值是灰色区域,两个决定都可以。再一次,这些数字没有神奇的意义。只是一些合理的参考。

我建议您考虑使用引用而不是堆分配。

于 2012-10-22T20:09:29.757 回答
0

您是否真的观察到了性能下降,然后追溯到这段代码?因为如果这只是一个理论问题,那么我建议您实际上以看起来直观和自然的方式编写代码。

完成这些并解决所有问题后,您可以运行程序并查看您实现的性能是否可以接受;如果不是,那么您可以着手优化实际瓶颈,而不是想象中的瓶颈。

Donald Knuth 说得最好:“我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源。”

于 2012-10-24T08:17:34.117 回答
0

在堆栈上复制 64 个字节很便宜。它几乎肯定比分配 64 字节便宜。如果您将 unique_ptr 用于在堆上分配的短期变量,您几乎肯定会失去效率。

如果你只是调用你的函数并立即使用返回值,它会很快。只有当您计划通过一系列矩阵返回函数传播矩阵时,您的效率损失才会变得显着。分配内存和使用 unique_ptr 的可行性取决于数据被重新返回的次数,而不是取决于数据的实际大小。

于 2012-10-24T08:39:32.357 回答
-1

为此使用动态数组太过分了。您不只是分配 64 个字节来保存 16 个浮点数。您正在为数组分配 4 个内存块,每个内存块都有一个用于堆管理的标头,以及每个 c++ 的数组大小,并且内部内存分配器通常会使用比您要求的更大的块,通常在块边界上对齐。

然后你就有了保存每个数组的结构的开销。例如。每个 std::array 是一个包含指向您的对象的指针的类,它至少为 8 个字节(指针为 4,数组长度为 4)x5。

而且您没有参考位置。矩阵中的每一行在内存中可能彼此相距很远。如果它们都彼此相邻,它们将在单个缓存行中被读取。

你最好只使用:

float matrix[4][4[

如果您需要它面向对象,请将其包装在一个类中:

class Matrix44 
{
    float matrix[4][4];
}

这样会更有效率。

于 2012-10-22T20:16:37.483 回答