2

I'm running the following code in Dev Studio 2010:

struct Foo
{
    Foo() {cout << "Foo()" << endl;}
    ~Foo() {cout << "~Foo()" << endl;}
    void operator ()(const int &) const {}
};

int bar[] = {0};
for_each(begin(bar), end(bar), Foo());

The output is not what I expected, and is the same in both debug and release regardless of the contents of the "bar" array:

Foo()
~Foo()
~Foo()
~Foo()

I've looked at the outputted assembly and I can't for the life of me understand why the compiler is generating extra calls to the destructor. Can anyone explain to me exactly what's going on?

Mark Feldman
  • 15,731
  • 3
  • 31
  • 58
  • 6
    Add `Foo(const Foo&) {cout << "Foo(const Foo&)" << endl;}` and try it. – Jesse Good Apr 02 '12 at 03:52
  • 1
    If you put prints in constructors it is best to do it for all the compiler generated methods as well. See a reference to the rule of 3/5 to get the compiler generated methods. – Martin York Apr 02 '12 at 05:14

2 Answers2

4

This is because nameless temporary objects are being created and destroyed during the course of the program.
Usually, the standard does not provide any guarantees w.r.t creation of temporary objects while using Standard Library containers and Algorithms. Implementations are allowed to create temporary objects if they desire so(for good performance or whatever).

Note that You should follow the Rule of Three in c++03 and Rule of Five in c++11 to avoid any problems due to temporary object creation.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • @MarkFeldman: No Problem. Do note my comment about *Rule of Three/Five*, it is rather an important one. – Alok Save Apr 02 '12 at 04:08
1

For each is a templated function, and in the case that you're using it, the parameter Foo will be typed as Foo, not as Foo& Foo*.

That means that the Foo object will be copied.

Why is it being copied twice? Once into the function, and once out. for_each will copy the anonymous Foo when it takes in the Foo arguement and then it will return a copy of it because its return type is also Foo.

To elaborate a tiny bit on what Als was saying: the copy constructor is being used.

To have it not copy, you could explicitly type it as a reference (though, as Als said, this would be implementation specific as theoretically for_each can make explicit copies if it wants):

for_each<Foo&>(..., ..., ...)
Corbin
  • 33,060
  • 6
  • 68
  • 78
  • Thanks for going into more detail Corbin, I added output to the copy constructor and saw exactly what I expected. I think I was getting confused because the presence of code in the constructor and destructor was causing calls to be explicitly made whereas the default copy contructor was being inlined (i.e. it was theoretically there, I didn't realize it). – Mark Feldman Apr 02 '12 at 03:56