3

我有一个用于串行存储器二维数组的类,它最初是一个ints 数组。现在我需要一个具有另一种类型的类似数组,我用模板重写了这个类;唯一的区别在于存储对象的类型:

template <class T>
class Serial2DArray
{
    ...
    T ** Content;
}

我有一些处理内容的测试函数,例如,一个使数组中的所有元素无效的函数(它们不是类成员,它们是处理Serial2DArray<int>对象的外部函数。我注意到现在它可以工作了 1-慢了 2% - 类中的所有其他代码都保持不变,唯一的区别是早期它只是一个普通类,int ** Content现在它是一个模板。

一个类似的问题:C++ 模板会使程序变慢吗?- 有意见认为只有编译会变慢(我可以明白为什么,编译器会为它在代码中找到的每个类生成类),但在这里我看到程序在运行时变慢 - 有什么合理的解释吗?

更新:问题在这里缩小了一点:https ://stackoverflow.com/a/11058672/1200000

Upd2:如评论中所述,这是变慢的功能:

#include <windows.h>
#include <mmsystem.h>
...
int Size = G_Width * G_Height * sizeof(int);
DWORD StartTime = timeGetTime();
for(int i=0; i<100; ++i)
{
    FillMemory(TestArray.Content[0], Size, 0);
}
MeasuredTime = timeGetTime() - StartTime;

这是实际的类模板:

#include <malloc.h>

template <class T>
class Serial2DArray
{
    public:
    Serial2DArray()
    {
        Content = NULL;
        Width = 0;
        Height = 0;
    }
    Serial2DArray(int _Width, int _Height)
    {
        Initialize(_Width, _Height);
    }
    ~Serial2DArray()
    {
        Deinitialize();
    }
    T ** Content;
    int GetWidth()
    {
        return Width;
    }
    int GetHeight()
    {
        return Height;
    }
    int Initialize(int _Width, int _Height)
    {
        // creating pointers to the beginning of each line
        if((Content = (T **)malloc(_Height * sizeof(T *))) != NULL)
        {
            // allocating a single memory chunk for the whole array
            if((Content[0] = (T *)malloc(_Width * _Height * sizeof(T))) != NULL)
            {
                // setting up line pointers' values
                T * LineAddress = Content[0];
                for(int i=0; i<_Height; ++i)
                {
                    Content[i] = LineAddress; // faster than Content[i] =
                    LineAddress += _Width;    // Content[0] + i * _Width;
                }
                // everything went ok, setting Width and Height values now
                Width = _Width;
                Height = _Height;
                // success
                return 1;
            }
            else
            {
                // insufficient memory available
                // need to delete line pointers
                free(Content);
                return 0;
            }
        }
        else
        {
            // insufficient memory available
            return 0;
        }
    }
    int Resize(int _Width, int _Height)
    {
        // deallocating previous array
        Deinitialize();
        // initializing a new one
        return Initialize(_Width, _Height);
    }
    int Deinitialize()
    {
        // deleting the actual memory chunk of the array
        free(Content[0]);
        // deleting pointers to each line
        free(Content);
        // success
        return 1;
    }
    private:
    int Width;
    int Height;
};

根据要求,二进制文件大小比较。

代码如下:

Serial2DArray<int> TestArray; 
Serial2DArray<int> ZeroArray;
  • 1 016 832 字节。

代码如下:

Serial2DArray TestArray; // NOT-template class with ints
Serial2DArray ZeroArray; // methods are in class declaration
  • 1 016 832 字节

代码如下:

Serial2DArray<int> TestArray;
Serial2DArray<int> ZeroArray;
Serial2DArray<double> AnotherArray;
Serial2DArray<double> YetAnotherArray;
  • 1 017 344 字节
4

2 回答 2

2

是的 - 随机基准可变性,更不用说整个程序速度较慢的事实可能与这个特定的类完全无关。

于 2012-06-15T21:31:27.017 回答
-2

在容器类中使用模板可能会导致已知的模板代码膨胀问题。粗略地说,它可能会导致程序中出现更多页面错误,从而降低性能。

那你为什么要问?因为模板会为模板的每个类实例而不是一个生成类,从而导致二进制产品中有更多页面,如果您愿意,可以使用更多代码页面。这可能会导致更多的页面错误,具体取决于您的运行时执行。

使用一个类模板实例和两个必须是最重的实例查看二进制文件的大小。它将让您了解新实例引入的新代码大小。

这是关于该主题的维基百科文章:代码膨胀文章。当强制编译器内联程序中的每个函数和方法时,问题可能是相同的,只要它可以与您的编译器一起使用。该标准试图通过使inline关键字成为编译器每次都不得遵循的“请求”来防止这种情况。例如,GCC 以中间语言生成您的代码,以评估生成的二进制文件是否不会导致代码膨胀,并可能因此丢弃内联请求。

于 2012-06-15T21:36:12.803 回答