在c ++中使用对象时对性能的影响

时间:2010-02-04 21:10:42

标签: c++ performance dynamic-programming compiler-optimization

我在C ++中有一个针对Knapsack的动态编程算法。当它作为函数实现并访问传递给它的变量时,在特定实例上运行需要22秒。当我把它作为我的类KnapsackInstance的成员函数并让它使用属于该类的数据成员的变量时,它开始需要37秒才能运行。据我所知,只有访问成员函数才能通过vtable,所以我无法解释可能发生的事情。

这是函数的代码

int KnapsackInstance::dpSolve() {
 int i; // Current item number
 int d; // Current weight
 int * tbl; // Array of size weightLeft
 int toret;
 tbl = new int[weightLeft+1];
 if (!tbl) return -1;
 memset(tbl, 0, (weightLeft+1)*sizeof(int));
 for (i = 1; i <= numItems; ++i) {
  for (d = weightLeft; d >= 0; --d) {
   if (profitsWeights.at(i-1).second <= d) {
    /* Either add this item or don't */
    int v1 = profitsWeights.at(i-1).first + tbl[d-profitsWeights.at(i-1).second];
    int v2 = tbl[d];
    tbl[d] = (v1 < v2 ? v2 : v1);
   }
  }
 }
 toret = tbl[weightLeft];
 delete[] tbl;
 return toret;
}

tbl是DP表的一列。我们从第一列开始,一直到最后一列。 profitsWeights变量是对的向量,其中第一个元素是利润,第二个元素是权重。 toret是值得回归的。

以下是原始函数的代码: -

int dpSolve(vector<pair<int, int> > profitsWeights, int weightLeft, int numItems) {
 int i; // Current item number
 int d; // Current weight
 int * tbl; // Array of size weightLeft
 int toret;
 tbl = new int[weightLeft+1];
 if (!tbl) return -1;
 memset(tbl, 0, (weightLeft+1)*sizeof(int));
 for (i = 1; i <= numItems; ++i) {
  for (d = weightLeft; d >= 0; --d) {
   if (profitsWeights.at(i-1).second <= d) {
    /* Either add this item or don't */
    int v1 = profitsWeights.at(i-1).first + tbl[d-profitsWeights.at(i-1).second];
    int v2 = tbl[d];
    tbl[d] = (v1 < v2 ? v2 : v1);
   }
  }
 }
 toret = tbl[weightLeft];
 delete[] tbl;
 return toret;
}

这是在Debian Lenny上运行的g ++ - 4.3.2和-O3 -DNDEBUG打开

由于

1 个答案:

答案 0 :(得分:3)

在典型的实现中,成员函数接收指向实例数据的指针作为隐藏参数(this)。因此,访问成员数据通常是通过指针,这可能会导致您看到的速度变慢。

另一方面,只需要查看一个版本的代码就很难做到。

在查看这两段代码后,我想我会更像这样编写成员函数:

int KnapsackInstance::dpSolve() {
    std::vector<int> tbl(weightLeft+1, 0);
    std::vector<pair<int, int> > weights(profitWeights);
    int v1;

    for (int i = 0; i <numItems; ++i) 
        for (int d = weightLeft; d >= 0; --d)
            if ((weights[i+1].second <= d) && 
                ((v1 = weights[i].first + tbl[d-weights[i-1].second])>tbl[d]))
                    tbl[d] = v1;
    return tbl[weightLeft];
}