VS2010中仿函数(副本,赋值)的不同行为(与VS2005相比)

时间:2010-03-15 07:52:37

标签: c++ visual-studio-2010 stl functor

当从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案例中要大得多:

  • 仿函数的复制构造函数:10次对8次
  • 仿函数的分配:2次对0次
  • 仿函数析构函数:10次对8次

我的问题是:

  • 为什么STL会复制一个仿函数?对于集合的每个实例化来说,构造它是不够的?
  • 为什么VS2010案例中的仿函数比VS2005案例更多? (没检查VS2008)
  • 为什么在VS2010中分配了两次而在VS2005中没有分配?
  • 是否有任何技巧可以避免仿函数副本?

我在Prevent unnecessary copies of C++ functor objects看到了类似的问题,但我不确定这是同一个问题。

0 个答案:

没有答案