当从VS2005移动到VS2010时,我们注意到性能下降,这似乎是由仿函数的额外副本引起的。
以下代码说明了该问题。必须有一个映射,其中值本身是一个集合。在地图和集合上,我们定义了一个比较函子(在示例中模板化)。
#include <iostream>
#include <map>
#include <set>
class A
{
public:
A(int i, char c) : m_i(i), m_c(c)
{
std::cout << "Construct object " << m_c << m_i << std::endl;
}
A(const A &a) : m_i(a.m_i), m_c(a.m_c)
{
std::cout << "Copy object " << m_c << m_i << std::endl;
}
~A()
{
std::cout << "Destruct object " << m_c << m_i << std::endl;
}
void operator= (const A &a)
{
m_i = a.m_i;
m_c = a.m_c;
std::cout << "Assign object " << m_c << m_i << std::endl;
}
int m_i;
char m_c;
};
class B : public A
{
public:
B(int i) : A(i, 'B') { }
static const char s_c = 'B';
};
class C : public A
{
public:
C(int i) : A(i, 'C') { }
static const char s_c = 'C';
};
template <class X>
class compareA
{
public:
compareA() : m_i(999)
{
std::cout << "Construct functor " << X::s_c << m_i << std::endl;
}
compareA(const compareA &a) : m_i(a.m_i)
{
std::cout << "Copy functor " << X::s_c << m_i << std::endl;
}
~compareA()
{
std::cout << "Destruct functor " << X::s_c << m_i << std::endl;
}
void operator= (const compareA &a)
{
m_i = a.m_i;
std::cout << "Assign functor " << X::s_c << m_i << std::endl;
}
bool operator() (const X &x1, const X &x2) const
{
std::cout << "Comparing object " << x1.m_i << " with " << x2.m_i << std::endl;
return x1.m_i < x2.m_i;
}
private:
int m_i;
};
typedef std::set<C, compareA<C> > SetTest;
typedef std::map<B, SetTest, compareA<B> > MapTest;
int main()
{
int i = 0;
std::cout << "--- " << i++ << std::endl;
MapTest mapTest;
std::cout << "--- " << i++ << std::endl;
SetTest &setTest = mapTest[0];
std::cout << "--- " << i++ << std::endl;
}
如果我用VS2005编译此代码,我会得到以下输出:
--- 0
Construct functor B999
Copy functor B999
Copy functor B999
Destruct functor B999
Destruct functor B999
--- 1
Construct object B0
Construct functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Copy object B0
Copy functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Copy object B0
Copy functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Destruct functor C999
Destruct object B0
Destruct functor C999
Destruct object B0
--- 2
如果我用VS2010编译它,我得到以下输出:
--- 0
Construct functor B999
Copy functor B999
Copy functor B999
Destruct functor B999
Destruct functor B999
--- 1
Construct object B0
Construct functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Copy object B0
Copy functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Copy functor C999
Assign functor C999
Assign functor C999
Destruct functor C999
Copy object B0
Copy functor C999
Copy functor C999
Copy functor C999
Destruct functor C999
Destruct functor C999
Copy functor C999
Assign functor C999
Assign functor C999
Destruct functor C999
Destruct functor C999
Destruct object B0
Destruct functor C999
Destruct object B0
--- 2
第一个语句(构建地图)的输出是相同的。
第二个语句的输出(在地图中创建第一个元素并获取对它的引用)在VS2010案例中要大得多:
我的问题是:
我在Prevent unnecessary copies of C++ functor objects看到了类似的问题,但我不确定这是同一个问题。