 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
al.anon@gmail.com Guest
|
Posted: Fri Apr 15, 2005 7:23 am Post subject: Curious about my Diagnosis |
|
|
I was learning some more of the STL and ran across for_each when I came
up with a simple example to use it:
#include <iostream>
#include <vector>
#include <algorithm>
class Dog {
public:
Dog(int x) : id(x){ std::cout << id << " livesn"; }
~Dog() { std::cout << id << " diedn"; }
void speak() {
std::cout << "Bark " << id << "n";
}
private:
int id;
};
int main() {
size_t dogs = 5;
std::vector
pound.reserve(dogs);
for (size_t i =0; i < dogs; i++) {
pound.push_back(Dog(i));
}
std::for_each(pound.begin(),pound.end(),std::mem_fun_ref(&Dog::speak));
}
I get some strange output when I run this code:
0 lives
0 died
1 lives
1 died
2 lives
2 died
3 lives
3 died
4 lives
4 died
Bark 0
Bark 1
Bark 2
Bark 3
Bark 4
0 died
1 died
2 died
3 died
4 died
I think I may understand it however. Does pound.push_back(Dog(i)) make
a temp Dog object that is then copied to the vector with the default
copy constructor, hence not calling the constructor again ? This would
explain the mismatch between number of constructor and number of
destructor calls.
If so is there any way to get rid of the temporary object ? I know I
could store pointers in the std::vector but then I need to delete them
before the vector goes out of scope and I can't store an auto_ptr in
the vector to take care of the deletion for me because of the
"assignment takes possession" issue of auto_ptr.
Just curious if there is an elegant solution, perhaps a way of calling
for_each on the vector to delete the objects whose pointers it holds.
Al
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Maxim Yegorushkin Guest
|
Posted: Fri Apr 15, 2005 9:23 am Post subject: Re: Curious about my Diagnosis |
|
|
On 15 Apr 2005 03:23:21 -0400, [email]al.anon (AT) gmail (DOT) com[/email] <al.anon (AT) gmail (DOT) com> wrote:
| Quote: | I was learning some more of the STL and ran across for_each when I came
up with a simple example to use it:
#include <iostream
#include
#include
class Dog {
public:
Dog(int x) : id(x){ std::cout << id << " livesn"; }
~Dog() { std::cout << id << " diedn"; }
void speak() {
std::cout << "Bark " << id << "n";
}
private:
int id;
};
int main() {
size_t dogs = 5;
std::vector
pound.reserve(dogs);
for (size_t i =0; i < dogs; i++) {
pound.push_back(Dog(i));
}
std::for_each(pound.begin(),pound.end(),std::mem_fun_ref(&Dog::speak));
}
|
[]
| Quote: | I think I may understand it however. Does pound.push_back(Dog(i)) make
a temp Dog object that is then copied to the vector with the default
copy constructor, hence not calling the constructor again ? This would
explain the mismatch between number of constructor and number of
destructor calls.
|
Just add these to see the whole picture:
Dog(Dog const& d) : id(d.id) { std::cout << id << " copiedn"; }
Dog& operator=(Dog const& d) { std::cout << (id = d.id) << "
copiedn"; }
| Quote: | If so is there any way to get rid of the temporary object ? I know I
could store pointers in the std::vector but then I need to delete them
before the vector goes out of scope and I can't store an auto_ptr in
the vector to take care of the deletion for me because of the
"assignment takes possession" issue of auto_ptr.
|
Using memory allocation to avoid temporaries may cost you more.
| Quote: | Just curious if there is an elegant solution, perhaps a way of calling
for_each on the vector to delete the objects whose pointers it holds.
|
A compiler may optimize the temporaries away.
Nevertheless, use a profiler to see if those temporaries are the source of
any hot spots before trying to get rid of them.
--
Maxim Yegorushkin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Fri Apr 15, 2005 9:25 am Post subject: Re: Curious about my Diagnosis |
|
|
"al.anon (AT) gmail (DOT) com" <al.anon (AT) gmail (DOT) com> writes:
| Quote: | #include <iostream
|
#include
| Quote: | #include <vector
#include
class Dog {
public:
Dog(int x) : id(x){ std::cout << id << " livesn"; }
~Dog() { std::cout << id << " diedn"; }
void speak() {
std::cout << "Bark " << id << "n";
}
private:
int id;
};
int main() {
size_t dogs = 5;
std::vector
pound.reserve(dogs);
for (size_t i =0; i < dogs; i++) {
pound.push_back(Dog(i));
}
std::for_each(pound.begin(),pound.end(),std::mem_fun_ref(&Dog::speak));
}
I get some strange output when I run this code:
0 lives
0 died
1 lives
1 died
2 lives
2 died
3 lives
3 died
4 lives
4 died
Bark 0
Bark 1
Bark 2
Bark 3
Bark 4
0 died
1 died
2 died
3 died
4 died
I think I may understand it however. Does pound.push_back(Dog(i)) make
a temp Dog object that is then copied to the vector with the default
copy constructor, hence not calling the constructor again?
|
The meaning is right, but the wording isn't quite. The generated
copy-constructor is also a constructor.
| Quote: | This would
explain the mismatch between number of constructor and number of
destructor calls.
|
The mismatch is in the output you generate, not in the numbers of
constructors and destructor calls. Implement the copy-constructor
yourself and add a statement generating output, and you'll see.
| Quote: | If so is there any way to get rid of the temporary object ?
|
I think that the compiler is allowed to optimize the temporary object
away. You might try increasing the optimization settings of your
compiler.
Apart from that, you can't do much (except creating the objects
dynamically, which you mention later). The STL containers deal with
values, not references.
| Quote: | I know I could store pointers in the std::vector but then I need to
delete them before the vector goes out of scope and I can't store an
auto_ptr in the vector to take care of the deletion for me because
of the "assignment takes possession" issue of auto_ptr.
|
boost::shared_ptr copes with this issue very well.
| Quote: | Just curious if there is an elegant solution, perhaps a way of calling
for_each on the vector to delete the objects whose pointers it holds.
|
Elegance is in the eye of the beholder.
Unless the temporary objects are a real problem, the present solution
is elegant already IMHO.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Stefan Näwe Guest
|
Posted: Fri Apr 15, 2005 9:27 am Post subject: Re: Curious about my Diagnosis |
|
|
[email]al.anon (AT) gmail (DOT) com[/email] schrieb:
| Quote: | [...]
If so is there any way to get rid of the temporary object ? I know I
could store pointers in the std::vector but then I need to delete them
before the vector goes out of scope and I can't store an auto_ptr in
the vector to take care of the deletion for me because of the
"assignment takes possession" issue of auto_ptr.
|
Why not use a std::vector<boost::shared_ptr ?
Stefan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Mary K. Kuhner Guest
|
Posted: Sat Apr 16, 2005 12:04 am Post subject: Re: Curious about my Diagnosis |
|
|
In article <1113531770.821786.156210 (AT) z14g2000cwz (DOT) googlegroups.com>,
[email]al.anon (AT) gmail (DOT) com[/email] <al.anon (AT) gmail (DOT) com> wrote:
| Quote: | I think I may understand it however. Does pound.push_back(Dog(i)) make
a temp Dog object that is then copied to the vector with the default
copy constructor, hence not calling the constructor again ? This would
explain the mismatch between number of constructor and number of
destructor calls.
|
Yes, the copy constructor is used to put the Dog in the vector.
Scott Meyer's _Effective STL_ has a really nice discussion of the way
the STL copies things around. For objects that are not expensive
to copy, it's often best just to accept this behavior.
| Quote: | If so is there any way to get rid of the temporary object ? I know I
could store pointers in the std::vector but then I need to delete them
before the vector goes out of scope and I can't store an auto_ptr in
the vector to take care of the deletion for me because of the
"assignment takes possession" issue of auto_ptr.
|
Boost's shared_ptr works well in this context, and if your Dogs
are expensive to copy, this may be the best solution. It seems
much more foolproof to me than writing something to delete the
Dog*'s in the vector--you could forget to do that easily, whereas
shared_ptr doesn't forget, and also won't delete a Dog when there
is still someone looking at it.
Mary Kuhner [email]mkkuhner (AT) eskimo (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Carl Barron Guest
|
Posted: Sat Apr 16, 2005 5:39 pm Post subject: Re: Curious about my Diagnosis |
|
|
Mary K. Kuhner <mkkuhner (AT) kingman (DOT) gs.washington.edu> wrote:
| Quote: | It seems
much more foolproof to me than writing something to delete the
Dog*'s in the vector--you could forget to do that easily, whereas
shared_ptr doesn't forget, and also won't delete a Dog when there
is still someone looking at it.
|
also something like this is a problem with raw ptrs.
std::vector<Dog *> dogs;
std::vector<Dog *> it = std::remove_if(dogs,begin(),dogs.end(),
some_functor());
all the removed Dog *'s are subject to leaking...
it probably looks something like this
which is not optimal but expository...
template <class For,class Pred>
For remove_if(For begin,For end,Pred pred)
{
For out(begin);
for(;begin!=endl;++begin)
{
if(!pred(*begin))
{
*out = *begin;
++out;
}
}
return out;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Paavo Helde Guest
|
Posted: Sun Apr 17, 2005 2:22 pm Post subject: Re: Curious about my Diagnosis |
|
|
"al.anon (AT) gmail (DOT) com" <al.anon (AT) gmail (DOT) com> wrote in
news:1113531770.821786.156210 (AT) z14g2000cwz (DOT) googlegroups.com:
| Quote: | std::vector<Dog> pound;
pound.reserve(dogs);
for (size_t i =0; i < dogs; i++) {
pound.push_back(Dog(i));
}
[...]
If so is there any way to get rid of the temporary object ?
|
As already mentioned, the compiler may optimize away the copy. If this is
not the case and the Dog objects are very expensive to copy, then you
might be able to define a fast default ctor and a fast swap() operation
for them and swap them into the vector:
for (size_t i =0; i < dogs; i++) {
Dog a_dog(i); // construct once
pound.push_back(Dog());
pound.back().swap(a_dog); // swap into place
}
(The initial reserve() call you already have becomes more essential in
this case).
However, I would not bother doing this unless the profiler shows a
bottleneck here.
Paavo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|