c++ - 使用 std::vector 分配的类比指针分配慢很多

标签 c++ memory-management c++11 benchmarking

我有一个用于处理数组分配的类。我的类很简单,定义如下:

DimArray.hpp:

#ifndef DIMARRAY_HPP_INCLUDED
#define DIMARRAY_HPP_INCLUDED

#include <vector>

template<typename T>
class DimArray
{
    private:
        int Width, Height;
        std::vector<T> Data;

    public:
        DimArray(int Width, int Height);
        DimArray(T* Data, int Width, int Height);
        DimArray(T** Data, int Width, int Height);

        DimArray(const DimArray &da);
        DimArray(DimArray &&da);

        inline int size() {return Width * Height;}
        inline int size() const {return Width * Height;}

        inline int width() {return Width;}
        inline int width() const {return Width;}

        inline int height() {return Height;}
        inline int height() const {return Height;}

        inline T* operator [](int Index) {return const_cast<T*>(Data.data()) + Height * Index;}
        inline const T* operator [](int Index) const {return Data.data() + Height * Index;}

        DimArray& operator = (DimArray da);
};

template<typename T>
DimArray<T>::DimArray(int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {}

template<typename T>
DimArray<T>::DimArray(T* Data, int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {std::copy(Data, Data + Width * Height, const_cast<T*>(this->Data.data()));}

template<typename T>
DimArray<T>::DimArray(T** Data, int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {std::copy(Data[0], Data[0] + Width * Height, const_cast<T*>(this->Data.data()));}

template<typename T>
DimArray<T>::DimArray(const DimArray &da) : Width(da.Width), Height(da.Height), Data(da.Data) {}

template<typename T>
DimArray<T>::DimArray(DimArray &&da) : Width(std::move(da.Width)), Height(std::move(da.Height)), Data(std::move(da.Data)) {}

template<typename T>
DimArray<T>& DimArray<T>::operator = (DimArray<T> da)
{
    this->Width = da.Width;
    this->Height = da.Height;
    this->Data.swap(da.Data);
    return *this;
}

#endif // DIMARRAY_HPP_INCLUDED

对于基准计时,我使用以下内容:

定时器.hpp:

#ifndef TIME_HPP_INCLUDED
#define TIME_HPP_INCLUDED

#include <chrono>

#if defined _WIN32 || defined _WIN64
#include <windows.h>

template<typename T>
class Timer
{
    private:
        typedef T duration;
        typedef typename T::rep rep;
        typedef typename T::period period;
        typedef std::chrono::time_point<Timer, duration> time_point;
        std::chrono::time_point<Timer, duration> Time;
        static const bool is_steady = true;

        const rep g_Frequency = []() -> rep
        {
            LARGE_INTEGER frequency;
            QueryPerformanceFrequency(&frequency);
            return frequency.QuadPart;
        }();

        inline std::chrono::time_point<Timer, duration> now()
        {
            LARGE_INTEGER count;
            QueryPerformanceCounter(&count);
            return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
        }

    public:
        inline void Start() {this->Time = this->now();}
        inline rep End() {return std::chrono::duration_cast<T>(this->now() - this->Time).count();}
};
#else
template<typename T>
class Timer
{
    private:
        static const bool is_steady = true;
        std::chrono::high_resolution_clock Clock;
        std::chrono::time_point<std::chrono::high_resolution_clock> Time;

    public:
        inline void Start() {this->Time = this->Clock.now();}
        inline T::rep End() {return std::chrono::duration_cast<T>(this->Clock.now() - this->Time).count();}
};
#endif

#endif // TIME_HPP_INCLUDED

我的基准如下:

int main()
{
    Timer<std::chrono::nanoseconds> T;

    T.Start();
    for (int i = 0; i < 100; ++i)
    {
        int** T2DArray = new int*[10000];
        for (int i = 0; i < 10000; ++i)
        {
            T2DArray[i] = new int[10000];
        }

        for (int i = 0; i < 10000; ++i)
        {
            delete[] T2DArray[i];
        }
        delete[] T2DArray;
    }
    std::cout<<T.End()<<" us\n\n";

    T.Start();
    for (int i = 0; i < 100; ++i)
    {
        DimArray<int> TwoDArray(10000, 10000);
    }
    std::cout<<T.End()<<" us\n\n";
}

它打印的结果是:

4.9599256 seconds  //for int**
42.9303941 seconds //for DimArray<int>

差别太大了!我不知道为什么?!

所以我改成了:

int main()
{
    Timer<std::chrono::nanoseconds> T;

    T.Start();
    for (int i = 0; i < 100; ++i)
    {
        int** T2DArray = new int*[10000];
        for (int i = 0; i < 10000; ++i)
        {
            T2DArray[i] = new int[10000];
        }

        for (int i = 0; i < 10000; ++i)
        {
            delete[] T2DArray[i];
        }
        delete[] T2DArray;
    }
    std::cout<<T.End()<<" us\n\n";

    T.Start();
    for (int i = 0; i < 100; ++i)
    {
        int* TwoDArray = new int[10000 * 10000];
        delete[] TwoDArray;
    }
    std::cout<<T.End()<<" us\n\n";
}

结果是:

4.6085725 seconds //for int**
0.1142958 seconds //for int*

与使用原始指针相比,使用 std::vector 的类为什么这么慢,有什么想法吗?

最佳答案

vector 会将它为您分配的内存归零。你的 new 代码给了你 “垃圾初始化”的内存。因此,分配 TwoDArray(10000, 10000) 为您提供一个全为零的数组,而 new int[10000 * 10000] 为您提供一个未定义内容的数组。 (仅仅观察会导致未定义的行为)

请注意,这意味着在 vector 情况下,您的程序实际上写入所有 100000000 int,而在 new 情况下您程序只为那么多 int 留出地址空间。

对于可比较的测量,您必须先将新阵列归零;例如使用 int* TwoDArray = new int[10000 * 10000](); 而不是 int* TwoDArray = new int[10000 * 10000];

关于c++ - 使用 std::vector 分配的类比指针分配慢很多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20863478/

相关文章:

c++ - 如何向 C++ 项目添加和使用 .zip(或 .pak)文件?

c++ - 使用 C++ 和 Qt 链接到网络驱动器

c++ - 在 C++ 的受控环境中执行 Windows 命令

c++ - 在 C++ 中,哪个是最昂贵的,删除最后一个元素或调整 vector 的大小?

c++ - 算法运行时间

c++ - constexpr 全局类类型

c++ - 在 C++ std::string 中解析(替换)

c - 关于重新分配的问题

c++ -::operator delete( void * ) 是否知道用::operator new( size_t ) 分配的内存大小

c++ - 在调用者的堆栈上分配内存