开发者

GCC 3.42 and VC2008 treat std::transform differently, take a reference or a copy of the functor?

I have Googled this functor-related topic, and it seems that people would generally say that the Standard Library will take a functor as a copy by default. Many examples have been found, and this is true for std::for_each. GCC and VC2008 compilers have yielded the same result: both take a copy of the functor.

But for std::transform I have found a difference in the testing code below:

#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.开发者_StackOverflow社区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
*/

The result seems to suggest that GCC takes MyFunctor as a reference while vc2008 takes it as a copy (just as both of them treat for_each).

Why do GCC and vc2008 behave differently in this matter, and which one should be the right practice?


The result seems to suggest that GCC takes MyFunctor as a reference while vc2008 takes it as a copy

You cannot infer this from your results. We have things like "copy elisions". The C++ standard explicitely allows the compiler to optimize unnecessary copies away in certain cases. It is entirely possible that libstdc++'s transform also takes the functor by value (I havn't checked) and that the G++ compiler simply gets rid of unnecessary copies. When a compiler performs a copy elision, it combines two or more objects into a single one. In your case, you created a temporary MyFunctor object. Then, there is another MyFunction object (the function's parameter). GCC is allowed to make this temporary the same object that the named function parameter refers to. In fact, whenever a new object is initialized with a temporary of the same type, the compiler is allowed to elide this copy and combine both objects into a single one.

Test this: Replace the temporary MyFunctor object with a variable name you declared earlier:

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

In this case, copy elision is not allowed because mf is not an rvalue but an lvalue. You can expect to see your copy-constructor print something.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜