constructing a new object and assignment in the same step - c++

const ClassA& curShot = vec_shots[curShotIndx];
In the above code the curShot object is constructed and assigned at the same step. My question is which constructor is used in the above statement. I thought it will be the default constructor followed by the assignment operator, but it seems to call the copy constructor instead. Why is that the case?

What happens is that
vec_shots[curShotIndx];
returns a reference which you assign to const ClassA& curShot. There is no object creation involved in this step. Therefore no constructor is invoked (neither default nor copy constructor).
The assignment operator is not invoked either since you are not assigning one object instance to another, but only a reference. You are not handling more than one (existing) object instance in this code. So, no construction or assignment is invoked.

Since you wrote "it seems to call copy constructor", I assume the ampersand in your question is a typo.
In that case, if you would do
const ClassA curShot = vec_shots[curShotIndx];
it is evaluated as copy construction. It is just the same as the ugly const ClassA curShot( vec_shots[curShotIndx] ).
However, if you write
ClassA curShot; // I skipped the "const", because otherwise the example would be invalid.
curShot = vec_shots[curShotIndx];
then a default constructor gets called and an opearator= is called on the second line.
Moreover, "=" so much can mean calling NEITHER copy constructor NOR operator=, that you can have this:
const ClassA f(){ return ClassA(); }
//...
const ClassA curShot = f(); // we would expect here a copy constructor call
Here -- if the compiler uses return value optimization and usually it does -- only a default constructor gets called for curShot.

No constructor is used, curShot is a reference, an alias to an already existing object, not a stand-alone object by itself.
Also, initialization and assignment cannot be done at the same step. For example, say you had
ClassA original;
ClassA copy = original;
Here, copy is not assigned original, it's initalized using original. This is called copy initialization.
If you did
ClassA copy2(original);
this would be called direct initialization.
The copy constructor would be called in both instances. (copy elision can occur, so it might not be called, but it must be available)
Assignment is when you use operator = on an already existing object:
ClassA x;
ClassA y;
x = y; //assignment

This statement just define curShot as a reference, it's not a new object.

Related

Arguments for the copy constructor

Why use references to the parameters of the copy constructor?
I found a lot of information saying that it is to avoid unlimited calls, but I still can't understand it.
When you pass to a method by value, a copy is made of the argument. Copying uses the copy constructor, so you get a chicken and egg situation with infinite recursive calls to the copy constructor.
Response to comment:
Passing by reference does not make a copy of the object begin passed. It simply passes the address of the object (hidden behind the reference syntax) so the object inside the copy constructor (or any method to which an object is passed by reference) is the same object as the one outside.
As well as solving the chicken-and-egg here, passing by reference is usually (for larger objects - larger than the size of a point) faster.
Response to further comment:
You could write a kind of copy constructor that passed by pointer, and it would work in the same way as passing by reference. But it would be fiddly to call explicitly and impossible to call implicitly.
Declaration:
class X
{
public:
X();
X(const X* const pOther);
};
The explicit copy:
X x1;
X x2(&x1); // Have to take address
The implicit copy:
void foo (X copyOfX); // Pass by value, copy made
...
X x1;
foo (x1); // Copy constructor called implicitly if correctly declared
// But not matched if declared with pointer
foo (&x1); // Copy construcxtor with pointer might (?) be matched
// But function call to foo isn't
Ultimately, such a thing would not be regarded as a C++ copy constructor.
This code:
class MyClass {
public:
MyClass();
MyClass(MyClass c);
};
does not compile. That is, because the second line here:
MyClass a;
MyClass b(a);
should theoretically cause the infinite loop you're talking about - it should construct a copy of a to before calling the constructor for b. However, if the copy constructor looks like this:
MyClass(const MyClass& c);
Then no copies are required to be made before calling the copy constructor.
From this webpage
A copy constructor is called when an object is passed by value. Copy
constructor itself is a function. So if we pass an argument by value
in a copy constructor, a call to copy constructor would be made to
call copy constructor which becomes a non-terminating chain of calls.
Therefore compiler doesn’t allow parameters to be passed by value.
By passing the argument by value the copy constructor calls itself, entering in an infinite 'recursion cycle'. The link above explain pretty well the basic topics about the copy constructor.

how does returning an object work with assignment operator?

Assume we have the following operation:
Object a = b.copy();
copy() is basically a method which copies an object and returns its copy.
Object copy()
{
Object copied_Object;
/..do the copy../
return copied_Object;
}
At first I thought the return would trigger an assignment operator = and place
the result at the right field of the operation, but it turned out that actually the copy constructor gets activated and then the Object created inside the function gets destroyed. This is what I know.
My question is, can you explain to me step by step what happens when Object a = b.copy(); is executed?
Object a = b.copy();
Is an instruction to create/construct/initialize an Object. No assignment is involved.
Assignments looks like this,
object = something;
Notice the absence of a declaration of object.
Now
Object a = b.copy();
constructs a, by a b.copy() of type Object, this requires Object to have the ability to be constructed by another Object. This is of course the copy constructor. Either the compiler generated, or a defaulted, or an explicit copy constructor.
When the statement is executed, the copy function will execute and transfer the created copied_Object to the caller by either
Copy construction
Copy elision, the compiler will invoke its black-magic box and construct Object a in-place. No copy construction necessary. As hinted by Jarod.
As LogicStuff, suggests you can do
Object copy()
{
return *this;
}
This copies the contents of the b object to the return value and requires a copy constructor.
I'll steal Daniel H's comment too and conclude that
Object a = b;
will carry the exact same semantics under normal circumstances. I.e. circumstances of least surprise.

how come invoking a constructor implicitly and invoking a constructor explicitly turns out to be same

I am new to c++.
I was told that invoking a constructor internally or externally are same.
Why is assignment operation not involved in the case of invoking constructor explicitly?
Object A(3) //implicit
Object A = Object(3); //explicit
I think an object will get created when we do Object(3);
So how are these two things turn out to be same?
Take a look at this answer for more on the subject, but assignment operator is invoked when you are dealing with an already existing object. You'll notice similar behaviour for copy constructors:
Object A;
// the following two lines will call the copy constructor
// even if the assignment operator is defined.
Object B = A;
Object C(A);

C++ Object Instantiation vs Assignment

What is the difference between this:
TestClass t;
And this:
TestClass t = TestClass();
I expected that the second might call the constructor twice and then operator=, but instead it calls the constructor exactly once, just like the first.
TestClass t;
calls the default constructor.
TestClass t = TestClass();
is a copy initialization. It will call the default constructor for TestClass() and then the copy constructor (theoretically, copying is subject to copy elision). No assignment takes place here.
There's also the notion of direct initialization:
TestClass t(TestClass());
If you want to use the assignment operator:
TestClass t;
TestClass s;
t = s;
The first case is quite simple - constructs an instance using the default constructor.
The second class is Constructing an anonymous object and then calling the copy constructor. Notice that here the = is not assignment, it's similar to (but not identical) writing:
TestClass t(TestClass());
We can verify that this needs the copy constructor to be available by making it unavailable, e.g.:
#include <iostream>
struct TestClass {
TestClass() { std::cout << "Ctor" << std::endl; }
TestClass(const TestClass&) = delete;
};
int main() {
TestClass t = TestClass();
}
Which fails to compile because of the deleted copy constructor. (In C++03 you can use private: instead).
What's actually happening most likely though is that your compiler is doing Return value optimisation, whereby it's allowed to ommit the call to the copy constructor entirely provided a suitable one exists and would be accessible.
In the first one, you are calling the default constructor implicitly. And in the second one you're calling it explicitly.
The latter one could call copy constructor and thus requires one to be public.
Edit: I certainly drew far too big conclusions from the type name you used. The sentence above only applies for class-types (i.e. not POD). For POD types, the former leaves the variable uninitialized, while the latter initializes it with so-called "default" value.

Pointer in copy constructor

I have a copy constructor that looks like this:
Qtreenode(const QtreeNode * & n) {
x=n->x;
y=n->y;
height=n->height;
width=n->width;
element=n->element;
}
I wrote this a week ago, and I looked back at it today and I was surprised by the line that when called the copy constructor with say swChild=new QtreeNode(*(n->swChild)); The arguement to the cc is a pointer by reference, right? But when I call it, I do (*(n->swChild)), which means the value of that child right? Why does my code work?
That is not a copy constructor. A copy constructor for a class is a constructor that takes a reference of the class's type. Any of the following would be copy constructors, though the second, taking a const reference, is by far the most commonly used:
QTreeNode(QTreeNode&);
QTreeNode(const QTreeNode&);
QTreeNode(volatile QTreeNode&);
QTreeNode(const volatile QTreeNode&);
Since this isn't a copy constructor, the implicitly declared copy constructor is still provided. It is declared as QTreeNode(const QTreeNode& n) and basically just copies each member of the class (i.e., it's a "shallow" copy, not a "deep" copy). It is this implicitly declared copy constructor that is used in your code.
That's not a copy constructor, it's just a regular old constructor. A copy constructor would take a const QtreeNode&, not a const QtreeNode*&.
Since you didn't define a copy constructor, the compiler made one for you. That's the one that is being called in the line swChild=new QtreeNode(*(n->swChild));, since you are passing a QtreeNode and not a pointer to one.