使用动态数组的类对象的重载运算符+=的奇怪性能

问题描述 投票:0回答:1

类对象定义如下:

class myArrayDynamic
{
private:
    unsigned m_n;
    double* m_data = nullptr;

public:

    // Copy constructor
    inline myArrayDynamic(const myArrayDynamic& a)
    {
        assert(m_n == a.m_n);

        for (int i = 0; i < m_n; ++i)
        {
            m_data[i] = a.m_data[i];
        }
    }

    // Move constructor
    inline myArrayDynamic(myArrayDynamic&& a)
    {
        m_n = a.m_n;
        m_data = a.m_data;
        a.m_data = nullptr;
    }

    inline myArrayDynamic(const unsigned n)
    :
        m_n(n)
    {
        this->m_data = new double[m_n];
    }

    inline myArrayDynamic(const unsigned n, const double& v)
    :
        m_n(n)
    {
        this->m_data = new double[m_n];
        for (unsigned i = 0; i < m_n; ++i)
        {
            this->m_data[i] = v;
        }
    }

    ~myArrayDynamic()
    {
        if (m_data) delete[] m_data;
    }

    // Copy assignment
    inline myArrayDynamic& operator=(const myArrayDynamic& a)
    {
        assert(m_n == a.m_n);

        for (int i = 0; i < m_n; ++i)
        {
            m_data[i] = a.m_data[i];
        }

        return *this;
    }

    // Move assignment
    inline myArrayDynamic& operator=(myArrayDynamic&& a)
    {
        m_n = a.m_n;
        m_data = a.m_data;
        a.m_data = nullptr;

        return *this;
    }

    inline myArrayDynamic& operator=(const double& v)
    {
        for (unsigned i = 0; i < m_n; ++i)
        {
            m_data[i] = v;
        }
        return *this;
    }

    inline myArrayDynamic& operator+=(const myArrayDynamic& m)
    {
        for (unsigned i = 0; i < m_n; ++i)
        {
            m_data[i] += m.m_data[i];
        }
        return *this;
    }

    inline double& operator[] (const unsigned i)
    {
        return m_data[i];
    }

    inline const double& operator[] (const unsigned i) const
    {
        return m_data[i];
    }

};

这是第一个测试代码:

        myArrayDynamic mDynamic(MN, 0.), mDynamic0(MN, 1.e-6);

        auto start = high_resolution_clock::now();
        for (int i = 0; i < iterMax; ++i)
        {
            mDynamic += mDynamic0;
        }
        auto end = high_resolution_clock::now();
        nanoseconds nsec = end - start;
        std::cout << "construct(N, v): "
                  << std::setprecision(3) << std::setw(10) << std::scientific
                  << nsec.count() * 1e-6 << " ms\n" << std::flush;

        std::cout << mDynamic[0] << "\n";

这是第二个测试代码:

        myArrayDynamic mDynamic(MN), mDynamic0(MN);
        mDynamic = 0.;
        mDynamic0 = 1.e-6;

        auto start = high_resolution_clock::now();
        for (int i = 0; i < iterMax; ++i)
        {
            mDynamic += mDynamic0;
        }
        auto end = high_resolution_clock::now();
        nanoseconds nsec = end - start;
        std::cout << "construct(N): "
                  << std::setprecision(3) << std::setw(10) << std::scientific
                  << nsec.count() * 1e-6 << " ms\n" << std::flush;

        std::cout << mDynamic[0] << "\n";

MN = 200; iterMax = 1000000
对于两个测试代码

唯一的区别是它们使用不同的构造函数

代码编译为(gcc版本9.4.0):

g++ -O3 -std=c++17 test.cpp -o test

在 ubuntu-20.04.3 上使用第 12 代 Intel(R) Core(TM) i7-12700H 运行代码

construct(N, v):  4.678e+01 ms
construct(N):  1.462e+01 ms

可以看出,上述测试代码的性能存在巨大差异

但是为什么呢?如何理解上述行为?

c++ performance oop dynamic-arrays
1个回答
0
投票

我有一点点改变。

#include <iostream>
#include <iomanip>
#include <chrono>

using namespace std;
using chrono::high_resolution_clock;
using chrono::nanoseconds;

class myArrayDynamic
{
private:
    unsigned m_n;
    double* m_data = nullptr;

public:

    inline myArrayDynamic(const unsigned n)
    :
        m_n(n)
    {
        //this->
        m_data = new double[m_n];
    }

    inline myArrayDynamic(const unsigned n, const double& v)
    :
        m_n(n)
    {
        //this->
        m_data = new double[m_n];
        for (unsigned i = 0; i < m_n; ++i)
        {
            //this->
            m_data[i] = v;
        }
    }

    ~myArrayDynamic()
    {
        if (m_data) delete[] m_data;
    }

    inline myArrayDynamic& operator=(const double& v)
    {
        for (unsigned i = 0; i < m_n; ++i)
        {
            m_data[i] = v;
        }
        return *this;
    }

    inline myArrayDynamic& operator+=(const myArrayDynamic& m)
    {
        for (unsigned i = 0; i < m_n; ++i)
        {
            m_data[i] += m.m_data[i];
        }
        return *this;
    }
} ;

int main() {
    const unsigned MN = 200, iterMax = 1000000;
  myArrayDynamic mDynamic(MN, 0.), mDynamic0(MN, 1.e-6);

  auto start = high_resolution_clock::now();
  for (int i = 0; i < iterMax; ++i)
  {
    mDynamic += mDynamic0;
  }
  auto end = high_resolution_clock::now();
  nanoseconds nsec = end - start;
  std::cout << "construct(N, v): "
    << std::setprecision(3) << std::setw(10) << std::scientific
                    << nsec.count() * 1e-6 << " ms\n" << std::flush;

  //std::cout << mDynamic[0] << "\n";
}


int main2() {
    const unsigned MN = 200, iterMax = 1000000;
  myArrayDynamic mDynamic(MN), mDynamic0(MN);
        mDynamic = 0.;
        mDynamic0 = 1.e-6;

        auto start = high_resolution_clock::now();
        for (int i = 0; i < iterMax; ++i)
        {
            mDynamic += mDynamic0;
        }
        auto end = high_resolution_clock::now();
        nanoseconds nsec = end - start;
        std::cout << "construct(N): "
                  << std::setprecision(3) << std::setw(10) << std::scientific
                  << nsec.count() * 1e-6 << " ms\n" << std::flush;

        //std::cout << mDynamic[0] << "\n";
}

myArrayDynamic
构造函数中,
this
代表类obj本身,不需要使用它们。 [仅在上面的例子中] 但实际上,编译器并不识别它,只是根据脚本进行编译。 所以你必须先调用 obj 本身,然后再次调用它的数组。 所以这就是为什么的答案。

© www.soinside.com 2019 - 2024. All rights reserved.