C++ 加速

源自:https://heavywatal.github.io/cxx/speed.html

介绍:

  •  编写程序不要附加超出优化程序所能带来的好处的成本。首先,编写一个程序来实现自己的目的很重要,考虑在自己认为程序是执行速率的限制,而不是自己本身的速率限制时对其进行重构。
  • 为实现程序的目的,需要避免时间复杂度过大,编写一个干净且易于维护的程序最终是富有成效的。
  • 除非是出于学习的目的,否则请避免重新发明轮子的想法。我正在尝试做的事情肯定已经被某人实现,应该以可重复使用的形式发布,首先 我将搜索标准库或Boost 或是Github 查看是否有符合我当前需要的轮子。

编译时间常数 constexpr

事先计算在编译时可以计算的内容并使其保持不变可以减少运行时的计算。constexpr由于它可以在C++11中明确修改,因此应该主动使用它。即使不能使用C++11,编译器也应该计算算术运算,例如常量的算术运算。

//每次乘法和除法
return 4.0 * M_PI * std::pow(radius, 3) / 3.0;


//只需乘以编译时间常数即可
constexpr double c = 4.0 * M_PI / 3.0;
return c * std::pow(radius, 3);

第二种运行的方式可能会更快一些。

内联扩展

函数调用成本很高,并且在使用短代码多次调用的函数中,它们是非常的昂贵的。可以通过编译器(内联扩展)的阶段扩展函数来消除这种成本。

对于跨文件的函数,请放置定义声明source.cpp 而不是定义声明。对于成员函数,只需要在类定义中将其作为定义声明。

-O2-finline-small-functions已开启, -O3-finline-functions开启时。由于可执行文件的大小已经过时并且编译被延迟,因此请考虑平衡。

inline int pow2(int x) {
    return x *= x;
}

功能对象

函数对象operator()定义为class 或 struct。 std::for_earch()、std::transform(),例如当通过在参数的函数的结束时,对于被称为多次小的功能,最好是使用功能对象,而不是在通过正常功能或函数指针。编译器似乎很容易优化,由于值可以作为成员变量保存,因此可能存在减少参数交换和内存分配/释放的场景。

class isAboveThreshold {
  public:
    isAboveThreshold(const double t): threshold_(t);
    bool operator()(const double x) const {
        return x > threshold_;
    }
  private:
    const double threshold_;
};

std::transform(v.begin(), v.end(), result.begin(), isAboveThreshold(3.14));

从C++11开始,Lambda表达很方便

const double threshold = 3.14;
std::transform(v.begin(), v.end(), result.begin(),
               [threshold](double x) -> bool {return x > threshold;});

不要创建额外的临时对象

正常编写程序时,会意外地创建不必要的临时对象。由于内存和CPU时间浪费,所以请尽量避免。

const通过引用或指针传递

因为按值复制对象成本较高,STL容器和手工类更快地通过引用传递。但是,由于没有解决引用的成本,简单类型(如int、double)应该通过普通 的值传递。

如果更改函数中引用传递的伪参数的内容,则调用者的实际参数的值也将更改,如果不打算更改,则应明确指定const。

void do_something(const std::vector& huge_array) {
    // 仅接收对象的引用而不进行复制
    // constがついているので、変更しようとするとコンパイルエラー
}

如果需要更改参数的内容,接受指针,调用时使用&,也可以高效地实现目的。

void do_something(std::vector* huge_array) {
    // 接收指针而不复制。    
    // 更改huge_array也会影响调用者
}

do_something(&some_array);  // 调用时传递参数的地址

容器

可参考http://en.cppreference.com/w/cpp/container

std::array:为C数组提供方便的成员函数的类,长度在编译时固定,并且在存储器上确保连续区域。元素访问非常高效,可以通过索引[]随机访问元素。

std::vector:它是可变长度的,也就是说,它array可以在执行时解压缩/减少。如果你暂时用C ++创建一个数组。将它设置insert()为中途已经很晚了(因为你必须在其他地方保留内存区域并将其全部复制)。

std::valarray:vector子物种预定义的函数/运算符,例如每个元素的算术运算。不仅方便,而且可能优化。但是,有一点是改变长度等弱点,因此使用场地有限。如果你想要全尺寸矢量运算/矩阵运算 ,那么使用Eigen和 Armadillo似乎更好。

std::deque:vector它几乎是一样的,但不支持reserve()。相反,push_front()和pop_front()可以使用和。换句话说,它是仅在需要添加/删除顶部时才使用的容器。

std::list:一个数组类,可以分散在离散的内存区域中。这是通过存储指示前一个和后一个元素的迭代器以及每个元素的值来实现的。因此,它insert()很快,因为它只重写迭代器。但是,它在这个范围内消耗额外的内存,它无法随机访问,并且与迭代器的总结很慢。

 

 

 

你可能感兴趣的:(C++,STL,C++)