Can I call a copy constructor explicitly?
Asked Answered
V

6

21

I'm a little confused as to the mechanics of the copy constructor. Correct me if I'm wrong:

If a method takes a reference to an object as a parameter, and the class defines a copy construtor, then the class uses the constructor to create a copy of itself and that gets passed to the function instead of a reference to the original object?

Furthermore, one can call

Object * obj = new Object(&anotherObject);

to create a copy of anotherObject?

Vietnam answered 6/2, 2010 at 17:11 Comment(4)
Your terminology shouldn't suggest that anotherObject is creating a copy of itself.. the object that is created after the new will be creating a copy of anotherObject.Bunk
@Hassan: Don't change the meaning of the question without asking the OP. That's an important distinction. &anotherObject is a pointer, not a reference.Rolfe
"one cannot tell" that new object(&anotherObject) will create a copy of another object implicitly (which is what the wording is suggesting). In order for that statement to hold true, the syntax needs adjusting.Bunk
Ok, you are right, perhaps I should have pointed it out.Bunk
S
30

No, if a function take a reference:

void f1( Object & o );   // call by reference

then no copy is made. If a function takes a value:

void f2( Object o );   // call by value

then a copy is created by the compiler using the copy constructor.

And yes, when you say:

Object * obj = new Object(anotherObject);   // not &anotherObject

the copy constructor is used explicitly (assuming anotherObject is of type Object.) There is nothing magic about the use of new here, however - in this case:

Object obj2(anotherObject);

the copy constructor is also used.

Spherics answered 6/2, 2010 at 17:13 Comment(1)
"then a copy is created by the compiler using the copy constructor." - it may use the move-constructor , and also this is a copy-elision scenario so perhaps even no constructor at all.Alkalinize
R
7

If a method takes a reference to an object as a parameter, copy constructor will not be called. If that was the case, then a call to the copy constructor itself would have resulted in an infinite loop (since it takes a reference as an argument).

That line is not a valid way to call a copy constructor. It expects a reference as an argument, not a pointer.

Rolfe answered 6/2, 2010 at 17:13 Comment(3)
Actually, the copy-constructor argument is not solid. The language standard allows optional copying in some cases and explicitly notes that the implementation has to make sure that there's no infinite recursion in case of copy-constructor, as one example (see footnote 93 in C++03)Cabal
@AndreyT: Interesting. Anyway, that doesn't change things in this case since we're talking about not copying in case of reference, which is a pretty sure thing.Rolfe
Well, the partion of standard I was referring to is actually about reference initialization, and it does explicitly allow copying in some situations (in case of const-reference initialization). Of course, compilers don't normally engage in wild unjustified copying, but examples of compiler creating weird illogical (yet still legal) copies are known.Cabal
C
3

The fact that you are making a method call is of no importance here. Reference parameter initialization during a function call is no different from a standalone reference initialization and is governed by the same rules.

The rules of reference initialization are a bit complicated, but the bottom line is that if the initializer is an lvalue (the argument in the method call in your case) and the type of the reference is the same as the type of the initializer (i.e. type of the parameter is the same as the argument type), then the reference will be bound directly. I.e. no copy is created.

Object a; // class type
Object &r = a; // no copying
const Object &cr = a; // no copying

If these requirements are not met (like if the initializer is an rvalue, for example), then it all depends. In some cases the copying might and will take place. For example

const Object &tr = Object();

can be interpreted by the compiler as

const Object &tr = Object(Object(Object(Object())));

with implementation-dependent finite number of copyings. Of course, for efficiency reasons compilers normally are trying not to create unnecessary copies, even when they are allowed to copy.

A classic example that often stirs debate about the validity of the copying behavior of the compiler is the reference initialization in expressions like the following one

Object a;
const Object &r = <some condition> ? a : Object();

A person familiar with C++ reference semantics would understand that expressions like the above are likely the rationale behind the standard permission to perform superfluous copying during reference initialization.

Cabal answered 6/2, 2010 at 17:28 Comment(2)
are you sure about that infinite depth thing? C++03 8.5.3 says that there are only two cases: (a) "The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object", and (b) "A temporary of type “cv1 T2” [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary" . Note that case (b) says bound to, not initialized from, so I don't see how that (b) permits any more than the one extra temporary.Alkalinize
Of course, C++14 (which came out after your answer was written) only allows case (a), i.e. no more temporaries can be created other than Object() . I didn't check C++11's wording although ISTR it had a defect regarding reference initialization from rvalues.Alkalinize
D
2

yes using placement new like so:

Object dstObject;
new(&dstObject) Object(&anotherObject);
Dunt answered 9/6, 2017 at 6:39 Comment(1)
The memory at dstObject should be sufficient for the new object to be placed. Otherwise it's undefined behavior #8025757Seymourseys
M
1

No in both the cases. In the first case, reference to that object itself is passed and copy is not created. In the second case you are passing a pointer to the constructor of object hence no copy is created. So object should have a constructor (not a copy constructor) which is something like object(anotherClass*)

Moye answered 6/2, 2010 at 17:14 Comment(0)
S
1

Copy constructor is called only when passing by value, not by reference. By reference no copying is needed (this is part of what references are for!) so no copy constructor called.

Sikang answered 6/2, 2010 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.