Why is the copy ctor called twice here?

R

richardclay09

The output of this:

#include <iostream>
#include <vector>
using namespace std;

struct X {
int i;
X(const X& x) : i(x.i) {
cout << "ctor copy: " << i << endl;
}
X(int ii) : i(ii) {
cout << "ctor by int: " << i << endl;
}
~X() {
cout << "dtor: " << i << endl;
}
};

int main(int argc, char **argv) {

vector<X> v;
v.push_back(X(100));

return 0;
}

Is this:

ctor by int: 100
ctor copy: 100
ctor copy: 100
dtor: 100
dtor: 100
dtor: 100

When you do the push_back, I can understand the vector wanting to make
its own copy, but why is this apparently done twice?
 
K

Karl Heinz Buchegger

The output of this:

#include <iostream>
#include <vector>
using namespace std;

struct X {
int i;
X(const X& x) : i(x.i) {
cout << "ctor copy: " << i << endl;
}
X(int ii) : i(ii) {
cout << "ctor by int: " << i << endl;
}
~X() {
cout << "dtor: " << i << endl;
}
};

int main(int argc, char **argv) {

vector<X> v;
v.push_back(X(100));

return 0;
}

Is this:

ctor by int: 100
ctor copy: 100
ctor copy: 100
dtor: 100
dtor: 100
dtor: 100

When you do the push_back, I can understand the vector wanting to make
its own copy, but why is this apparently done twice?

From the language point of view, there is no specific reason. Ask in a newsgroup
dedicated to your particular compiler. It could be an error in its vector-implementation.
 
C

Chris Jefferson

The output of this:
<snip program>
Is this:

ctor by int: 100
ctor copy: 100
ctor copy: 100
dtor: 100
dtor: 100
dtor: 100

When you do the push_back, I can understand the vector wanting to make
its own copy, but why is this apparently done twice?

On my compiler (g++ 3.3), I get what you would expect, namely:

ctor by int: 100
ctor copy: 100
dtor: 100
dtor: 100

I am unsure why your vector is behaving differently. It is possible
push_back takes it's input by value rather than by reference (which
would be wrong), or that the vector is deciding to extend earlier than
is necessary (which would also be wrong), or something else. You could
if you wish explore this by looking at the source to vector, which
should be included in your compiler (as very few compilers can compile
templates seperatly and therefore include the source in the headers).

Unfortunatly I suspect it's unlikely such a bug would be fixed so you
may have to upgrade your compiler (although you can always report it)

Chris
 
G

Gary Labowitz

Chris Jefferson said:
On my compiler (g++ 3.3), I get what you would expect, namely:

ctor by int: 100
ctor copy: 100
dtor: 100
dtor: 100

Odd! On my compiler (g++ 3.4.2) I get
ctor by int: 100
ctor copy: 100
dtor: 100

Something is afoot!
 
A

Andrey Tarasevich

...
int main(int argc, char **argv) {

vector<X> v;
v.push_back(X(100));

return 0;
}

Is this:

ctor by int: 100
ctor copy: 100
ctor copy: 100
dtor: 100
dtor: 100
dtor: 100

When you do the push_back, I can understand the vector wanting to make
its own copy, but why is this apparently done twice?

It is possible that the first copy is made when the compiler initializes
the [constant reference] parameter of 'push_pack' with a temporary
object 'X(100)'. 'X(100)' is not an lvalue, which means that in
accordance with 8.5.2/5 the compiler is allowed to create an extra copy
of the object when initializing that reference (actually, in this case
the compiler is allowed create as many extra copies as it wants).

The second copy constructor call takes place when the parameter of
'push_pack' is transferred to the actual vector memory.

Apparently, some internal quirk of the compiler caused it to create that
unnecessary first copy (although there's nothing illegal in it). AFAIK,
most compilers won't do it.
 
M

Mike Wahler

sadhu said:
Why would push_back taking input by value be wrong?

Because the C++ standard defines its parameter
as a const reference.

=============================
ISO/IEC 14882:1998(E)

23.2.4 Template class vector

// 23.2.4.3 modifiers:
void push_back(const T& x);
=============================


-Mike
 
A

adbarnet

I think this is shabby re-allocation on the MS compiler (it is MS we're
talking about here right?)

if you provide a default constructor for X, and replace your main with:
int main(int argc, char** argv)
{
const X & x1(100);

vector<X> v;

v.reserve(1);

std::cout << "\n\n" << std::endl;

v.push_back(x1);

return 0;

}

You can get a clearer idea of where the copies are taking place - explicitly
instantiating as a reference removes any copy it may have caused when
created via the push_back parameter - and yet if you remove the reserve(1)
the same behaviour you are seeing repeats - which means in my book it's just
bad re-allocation when inserting in the vector.


regards,

Aiden.
 
A

Andrey Tarasevich

adbarnet said:
if you provide a default constructor for X, and replace your main with:

Why do you think 'X' needs a default constructor? In the code below I
don't see any place where it might be necessary.
 
D

Dave Townsend

Gary Labowitz said:
Odd! On my compiler (g++ 3.4.2) I get
ctor by int: 100
ctor copy: 100
dtor: 100

Something is afoot!
I noticed similar behavior when I ran this example in VC++, I was a little
curious why the destructor calls
didn't match the constructor calls. I had a breakpoint on the main return
statement, and only saw the one destructor call. However, if you continue
after the return, the second
destructor is triggered as we leave the main() scope. The behavior you
reported above is certainly incorrect
otherwise.

dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,830
Latest member
HeleneMull

Latest Threads

Top