在类中与外部定义函数的性能

时间:2015-03-17 10:23:53

标签: c++ oop

我正在编写一个程序来玩棋盘游戏Quoridor。我使用minimax搜索和自定义类来存储状态。我的问题是:在类中定义函数A.或者在类之外定义函数是否有任何性能差异,并传递指针。

我的直觉(这可能是错误的)是在情况A中,它会导致一些内存开销,因为类的每个对象都有自己的所有函数的副本。这也会减慢创建对象的速度,因为除了数据成员之外,还必须创建函数。

我的另一个问题是,对于构造函数返回的默认对象 - 使用构造函数或复制预先存在的对象会更快吗?

这是该课程的代码:

class BGraph {
public:
    int rows;
    int columns;
    int walls;

    int row1;
    int column1;
    int walls1;

    int row2;
    int column2;
    int walls2;

    float time;

    // Stores whether a wall has been placed at a vertex.
    vector<int> wallsList;

    vector<set<int> > edges;

    void addEdge(int v1, int v2) {
        if (v1 > v2) {
            int t2 = v2;
            v2 = v1;
            v1 = t2;
        }
        edges[v1].insert(v2);
    }

    void removeEdge(int v1, int v2) {
        if (v1 > v2) {
            int t2 = v2;
            v2 = v1;
            v1 = t2;
        }
        edges[v1].erase(v2);
    }

    bool checkEdge(int v1, int v2) {
        if (v1 > v2) {
            int t2 = v2;
            v2 = v1;
            v1 = t2;
        }
        return edges[v1].find(v2) != edges[v1].end();
    }

    //Take row and column, return the vertex number.
    //For example, 1,1 -> 1, 2,1 -> row_length + 1
    int rc2v(int r, int c) {
        return columns * (r - 1) + c;
    }

    //Take vertex number, return (row,column)
    pair<int, int> v2rc(int v) {
        pair<int, int> ans;
        ans.first = v / columns + 1;
        ans.second = v % columns;
        if (ans.second == 0) {
            ans.second = columns;
        }
        return ans;
    }

    void addWall(Wall wall) {
        if (wall.horizontal) {
            removeEdge(rc2v(wall.row, wall.column - 1), rc2v(wall.row, wall.column));
            removeEdge(rc2v(wall.row - 1, wall.column - 1), rc2v(wall.row - 1, wall.column));
            wallsList[rc2v(wall.row, wall.column)] = 1;
        } else {
            removeEdge(rc2v(wall.row - 1, wall.column), rc2v(wall.row, wall.column));
            removeEdge(rc2v(wall.row - 1, wall.column - 1), rc2v(wall.row, wall.column - 1));
            wallsList[rc2v(wall.row, wall.column)] = 2;
        }
    }

    //There are two conditions - the edges that it is trying to break should EXIST.
    bool wallIsLegal(Wall wall) {
        if (wall.row <= rows && wall.row > 1 && wall.column <= columns && wall.column > 1) {
            if (wall.horizontal) {
                return checkEdge(rc2v(wall.row, wall.column - 1), rc2v(wall.row, wall.column))
                        & checkEdge(rc2v(wall.row - 1, wall.column - 1), rc2v(wall.row - 1, wall.column))
                        & wallsList[rc2v(wall.row, wall.column)];
            } else {
                return checkEdge(rc2v(wall.row - 1, wall.column), rc2v(wall.row, wall.column))
                        & checkEdge(rc2v(wall.row - 1, wall.column - 1), rc2v(wall.row, wall.column - 1))
                        & wallsList[rc2v(wall.row, wall.column)];
            }
        } else {
            return false;
        }
    }

    //Removes/adds edges to account for the presence of a player.
    void adjustForPlayer(int player){

        int i,j;
        if (player == 1) {
                i = row1;
                j = column1;
            } else {
                i = row2;
                j = column2;
            }

            bool e1 = (checkEdge(rc2v(i, j - 1), rc2v(i, j))); //h-x
            bool e2 = (checkEdge(rc2v(i, j), rc2v(i, j + 1))); //x-d
            bool e3 = (checkEdge(rc2v(i - 1, j), rc2v(i, j))); //b-x
            bool e4 = (checkEdge(rc2v(i, j), rc2v(i + 1, j))); //f-x

            if (e1 && e2) {
                removeEdge(rc2v(i, j - 1), rc2v(i, j));
                removeEdge(rc2v(i, j), rc2v(i, j + 1));
                addEdge(rc2v(i, j - 1), rc2v(i, j + 1));
            } else if (e1 && !e2) {
                removeEdge(rc2v(i, j - 1), rc2v(i, j));
                if (e3)
                    addEdge(rc2v(i, j - 1), rc2v(i - 1, j));
                if (e4)
                    addEdge(rc2v(i, j - 1), rc2v(i + 1, j));
            } else if (!e1 && e2) {
                removeEdge(rc2v(i, j), rc2v(i, j + 1));
                if (e3)
                    addEdge(rc2v(i - 1, j), rc2v(i, j + 1));
                if (e4)
                    addEdge(rc2v(i + 1, j), rc2v(i, j + 1));
            }

            if (e3 && e4) {
                removeEdge(rc2v(i - 1, j), rc2v(i, j));
                removeEdge(rc2v(i, j), rc2v(i + 1, j));
                addEdge(rc2v(i - 1, j), rc2v(i + 1, j));
            } else if (e3 && !e4) {
                removeEdge(rc2v(i - 1, j), rc2v(i, j));
                if (e1)
                    addEdge(rc2v(i - 1, j), rc2v(i, j - 1));
                if (e2)
                    addEdge(rc2v(i - 1, j), rc2v(i, j + 1));
            } else if (!e3 && e4) {
                removeEdge(rc2v(i, j), rc2v(i + 1, j));
                if (e1)
                    addEdge(rc2v(i + 1, j), rc2v(i, j - 1));
                if (e2)
                    addEdge(rc2v(i + 1, j), rc2v(i, j + 1));
            }
    }

    BGraph(int r, int c, int k, int t) {
        rows = r;
        columns = c;
        walls = k;
        time = t;

        row1 = r;
        column1 = c / 2 + 1;
        walls1 = k;
        row2 = 1;
        column2 = c / 2 + 1;
        walls2 = k;

        //r*c+1 so that we don't have to worry about the fact that these things are actually indexed from zero.
        wallsList = vector<int>(r*c+1, 0);

        for (int i = 1; i <= r * c + 1; i++) {
            set<int> s;
        }

        //Initialise horizontal edges.
        for (int i = 1; i <= r; i++) {
            for (int j = 1; j < c; j++) {
                addEdge(rc2v(i, j), rc2v(i, j + 1));
            }
        }

        //Initialise vertical edges.
        for (int j = 1; j <= c; j++) {
            for (int i = 1; i < r; i++) {
                addEdge(rc2v(i, j), rc2v(i + 1, j));
            }
        }
    }

    //Copy Constructor
    BGraph(const BGraph & obj){
        rows = obj.rows;
        columns = obj.columns;
        walls = obj.walls;

        row1 = obj.row1;
        column1 = obj.column1;
        walls1 = obj.walls1;

        row2 = obj.row2;
        column2 = obj.column2;
        walls2 = obj.walls2;

        time = obj.time;

        wallsList = obj.wallsList;
        edges = obj.edges;
    }

};

1 个答案:

答案 0 :(得分:1)

关于你的两个问题:

1)在定义类内外的函数时是否存在性能差异?

如果您将功能定义为非虚拟功能,那么在定义类外的功能方面,您在性能方面没有任何区别。

每个成员非静态函数都有一个隐含参数this,这将导致函数的原型,其中指针作为在类外定义的参数。

代码示例举例说明:

  class A {
    void foo(){};
  }

  void outsideFoo(A* ptr);

  // A::foo() true signature is A::foo(A* this) 
  // which is identical to outsideFoo(A* ptr)

非虚函数在编译时解析,因此您将具有相同数量的间接。

如果函数是虚拟的,那么它们将比在类外定义函数慢,因为在运行时会在虚函数表中进行搜索,然后跳转到函数。

我会为你的情况提供一些在你的类中使用非虚拟函数的方法,因为它会带来代码清晰度。

2)构造函数与复制构造函数

在您的情况下,由于您正在进行深层复制,因此它们的速度都很快。

调用构造函数与复制构造函数的性能差异由实现定义。例如,如果您对数据进行了一些改进,例如生成数据的空间划分或数据的排序,那么复制构造函数会更快,因为它只会复制已生成的空间分割/排序数据。

但是,如果您只是简单地在两者中分配/设定值,那么性能将是相同的。