C++ GCC 3.42和VC2008对std::transform的处理方式不同,是引用还是复制函子?

C++ GCC 3.42和VC2008对std::transform的处理方式不同,是引用还是复制函子?,c++,stl,reference,functor,C++,Stl,Reference,Functor,我在谷歌上搜索了这个与函子相关的主题,似乎人们通常会说,默认情况下,标准库将函子作为副本。已经找到了许多例子,对于std::for_each,情况也是如此。GCC和VC2008编译器产生了相同的结果:它们都复制了函子 但是对于std::transform我在下面的测试代码中发现了差异: #include <iostream> #include <vector> using namespace std; #define MSG(msg) cout << msg

我在谷歌上搜索了这个与函子相关的主题,似乎人们通常会说,默认情况下,标准库将函子作为副本。已经找到了许多例子,对于
std::for_each
,情况也是如此。GCC和VC2008编译器产生了相同的结果:它们都复制了函子

但是对于
std::transform
我在下面的测试代码中发现了差异:

#include <iostream>
#include <vector>

using namespace std;
#define MSG(msg) cout << msg << endl;

struct MyFunctor{
    MyFunctor()
    {
        MSG("MyFunctor constructor");
    }

    MyFunctor(const MyFunctor& myf)
    {
        MSG("MyFunctor copy constructor");
    }

    ~MyFunctor()
    {
        MSG("MyFunctor destructor");
    }
    int operator()(int i)
    {
        i = -(i+1);
        return i;
    }
};

int main() 
{
    vector<int> myvec;
    myvec.push_back(1);
    myvec.push_back(1);
    myvec.push_back(1);
    myvec.push_back(1);
    std::transform(myvec.begin(),myvec.end(),myvec.begin(),MyFunctor());
    system("pause");
}

/*
gcc result:
MyFunctor constructor
MyFunctor destructor

vc2008 result:
MyFunctor constructor
MyFunctor copy constructor
MyFunctor copy constructor
MyFunctor destructor
MyFunctor destructor
MyFunctor destructor
*/
#包括
#包括
使用名称空间std;
#定义MSG(MSG)cout
结果似乎表明,GCC将MyFunctor作为引用,而vc2008将其作为副本

你不能从你的结果中推断出这一点。我们有“复制省略”之类的东西。C++标准明确地允许编译器在某些情况下优化不必要的副本。libstdc++的转换也可能按值获取函子(我没有检查),而G++编译器只是简单地消除了不必要的副本。当编译器执行复制省略时,它将两个或多个对象合并为一个对象。在本例中,您创建了一个临时MyFunctor对象。然后,还有另一个MyFunction对象(函数的参数)。GCC可以使这个临时对象与命名函数参数所引用的对象相同。事实上,每当使用相同类型的临时对象初始化一个新对象时,编译器都可以省略该副本,并将两个对象合并为一个对象

测试:用前面声明的变量名替换临时MyFunctor对象:

MyFunctor mf;
...
std::transform(...,mf);

在这种情况下,不允许复制省略,因为mf不是右值而是左值。您可以看到复制构造函数打印一些东西。

您是否在启用优化的发布模式下编译?这看起来只是GCC内联了对
transform
的调用并省略了副本。是的,它只是其中一个副本的一个副本省略。但是VS2008除了必要的拷贝外,还生成了3个额外的拷贝。我一直在使用启用优化的发布模式。是的,Sellibitz你是对的,是拷贝省略造成了混乱。尽管VC2008编译器与gcc编译器(仅1个副本)相比,仍然多生成了3个函子副本(总共4个)。@Gob00st:编译器本身不应受到责备。它还取决于标准库实现。:)是的,把拷贝省略放在一边,VC2008编译器仍然调用拷贝构造函数3次以上,这是为什么?我已经尝试了完全优化和发布模式,仍然!