我正在编写一个程序来玩棋盘游戏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;
}
};
答案 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)构造函数与复制构造函数
在您的情况下,由于您正在进行深层复制,因此它们的速度都很快。
调用构造函数与复制构造函数的性能差异由实现定义。例如,如果您对数据进行了一些改进,例如生成数据的空间划分或数据的排序,那么复制构造函数会更快,因为它只会复制已生成的空间分割/排序数据。
但是,如果您只是简单地在两者中分配/设定值,那么性能将是相同的。