C++ 运算符()非常耗时(在C+;+;)中分析)

C++ 运算符()非常耗时(在C+;+;)中分析),c++,profiling,montecarlo,C++,Profiling,Montecarlo,我有一个用户定义的2D数组存储在一个连续的内存块中,因此重载了()操作符 void CheckIndex(int& i, int& j) const //checks for index out of bounds error { if ( i < -nghost || i >= cols_x+nghost || j < -nghost || j >= rows_y+nghost ) { std::cout <

我有一个用户定义的2D数组存储在一个连续的内存块中,因此重载了()操作符

void CheckIndex(int& i, int& j) const //checks for index out of bounds error 
{
  if ( i < -nghost || i >= cols_x+nghost ||
       j < -nghost || j >= rows_y+nghost )
    {
      std::cout << "Index out of bounds. Exiting."
        << std::endl;
      exit(EXIT_FAILURE);
    }
}

double& operator()(int i, int j) const
{
  CheckIndex(i,j);
  int jump = cols_x + 2*nghost;
  return mesh[ (i+nghost) + (j+nghost)*jump ];
}
double& operator()(int i, int j); //implementation same as above
void CheckIndex(int&i,int&j)const//检查索引越界错误
{
如果(i<-nghost | i>=cols|ux+nghost||
j<-nghost | | j>=行(y+nghost)
{

Std::Po>边界检查是众所周知的慢。早期CPU甚至有一个特殊的功能,它的性能影响很大。即使在今天,C++定义了<代码> STD::vector::在/<代码>进行边界检查,并离开普通的<代码> vector::运算符[]/COND>未检查。< /P> 这是有道理的。
操作符[]
的大多数关键用法都是在循环中使用的,您只需要检查循环边界。整个循环中间是安全的

C++有更多的方法使循环安全。像
for(element:collection)
这样的习惯用法不会强迫您编写边界,因此您也不会弄错

作为一个小优化,C++20允许

  if ( i < -nghost || i >= cols_x+nghost ||
       j < -nghost || j >= rows_y+nghost )
    {
      [[unlikely]]
      std::cout << "Index out of bounds. Exiting.\n";
      exit(EXIT_FAILURE);
    }
if(i<-nghost | i>=cols|ux+nghost||
j<-nghost | | j>=行(y+nghost)
{
[[不太可能]]

Std::Po>边界检查是众所周知的慢。早期CPU甚至有一个特殊的功能,它的性能影响很大。即使在今天,C++定义了<代码> STD::vector::在/<代码>进行边界检查,并离开普通的<代码> vector::运算符[]/COND>未检查。< /P> 这是有道理的。
操作符[]
的大多数关键用法都是在循环中使用的,您只需要检查循环边界。整个循环中间是安全的

C++有更多的方法使循环安全。像
for(element:collection)
这样的习惯用法不会强迫您编写边界,因此您也不会弄错

作为一个小优化,C++20允许

  if ( i < -nghost || i >= cols_x+nghost ||
       j < -nghost || j >= rows_y+nghost )
    {
      [[unlikely]]
      std::cout << "Index out of bounds. Exiting.\n";
      exit(EXIT_FAILURE);
    }
if(i<-nghost | i>=cols|ux+nghost||
j<-nghost | | j>=行(y+nghost)
{
[[不太可能]]


std::cout
operator();
在每次迭代中检查索引是一种浪费。确保索引正确是调用方的责任i使用
操作符()的实现进行编辑
还请注意,
15%
可能只是因为
15%
您的工作负载实际上正在访问元素。在这种情况下,
15%
本身并不是一个问题,尽管仍然是提高总体性能的一个很好的候选者
检查索引的实现缺失,并且是一个典型的用例。15%来自?请阅读
operator()
速度慢的原因很可能在代码中。
checkindex
的问题可能很容易解决:不要检查每次访问的索引。例如,在一个紧密循环中
for(int i=0;i
在每次迭代中检查索引是一种浪费。确保索引正确是调用方的责任i使用
操作符()的实现进行编辑
还请注意,
15%
可能只是因为
15%
您的工作负载实际上正在访问元素。在这种情况下,
15%
本身并不是一个问题,尽管仍然是提高总体性能的一个很好的候选者
检查索引的实现缺失,并且是一个典型的用例。15%来自?请阅读相关内容,以便解决方案是检查
()
可以在进入循环之前进行假设。@Angelos如果使用eg迭代器,实际上不需要进行检查,因为很难出错,只需使用
begin
end
。使用基于范围的for循环,你甚至没有机会错误地键入
being
end
,因为这都是隐藏的,但是怎么可能呢当我的数组由原始指针
double*
实现时,我使用迭代器,我不确定是否可以避免这种情况,因为我需要使用FFTW3库。@Angelos:FFTW3需要的是连续内存分配。
new double[]
是连续的,但std::vector也是连续的。后者更安全。不过,您需要将有效边界传递给FFTW3,否则它将访问未分配的内存。这显示了一般模式:小心边界;然后单个元素访问将是安全的。如果我更改为
std::vector
,那么我应该删除Ru我已经实现了5的le,对吗?不需要析构函数等?所以解决方案可以是检查
()
可以在进入循环之前进行假设。@Angelos如果使用eg迭代器,实际上不需要进行检查,因为很难出错,只需使用
begin
end
。使用基于范围的for循环,你甚至没有机会错误地键入
being
end
,因为这都是隐藏的,但是怎么可能呢当我的数组由原始指针
double*
实现时,我使用迭代器,我不确定是否可以避免这种情况,因为我需要使用FFTW3库。@Angelos:FFTW3需要的是连续内存分配。
new double[]
是连续的,但std::vector也是连续的。后者更安全。不过,您需要将有效边界传递给FFTW3,否则它将访问未分配的内存。这显示了一般模式:小心边界;然后单个元素访问将是安全的。如果我更改为
std::vector
,那么我应该删除Ru我已经实现了5的le,对吗?不需要析构函数等?