Copy Constructor is not invoked [duplicate] - c++

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why copy constructor is not called in this case?
Consider the sample program below:
#include <iostream>
using namespace std;
class sample
{
private:
int x;
public:
sample(int a=0) : x(a)
{
cout << "default ctor invoked\n";
}
sample(const sample& obj)
{
cout << "copy ctor invoked\n";
}
};
int main()
{
sample s2 = sample(20); //Line1
sample s3 = 20; //Line2
return 0;
}
In Line1, first the constructor of sample class is invoked explicitly with the argument 20. Then i expected the copy constructor to be invoked to initialize s2.
In Line2, first the constructor of sample class is invoked implicitly first with the argument 20. Here also i expected the copy constructor to be invoked to initialize s2.
In both cases, the copy constructor is not invoked? Why is this happening? I believe, there is something wrong with my understanding of the invocation of copy constructor. Could someone correct me where i am going wrong?

This is expected. It's called copy elision.
Your expectation is correct, but they made an exception in C++ (for performance) which allows the compiler to treat your expression as direct initialization of one instance while bypassing the copy constructor.

in first line it does not invoke copy constructor because you do not copy an object. You are assigning one object to other. C++ provide default = operator which perform shallow copy. And this is invoked implicitly. The constructor is called for right hand object and default constructor is invoked for the left hand object. After that default = operator is invoked.
For line 2, it use constructor that takes int parameters that you define. It is actually converter constructor because it takes an integer and creates object of your class. Thats why c++ use this as a converter constructor and when you try to assign an integer to your object, c++ invokes inplicitly this converter constructor.
I hope this helps you to understand.

Related

Error spotted in C++ Primer 5th Edition (copy intialization vs direct initialization)

Hi i am trying to understand how copy constructor works and looking at an example. The example is as follows:
{//new scope
Sales_data *p = new Sales_data;
auto p2 = make_shared<Saled_data>();
Sales_data item(*p); // copy constructor copies *p into item
vector<Sales_data> vec;
vec.push_back(*p2);// copies the object to which p2 points
delete p;
}
My question is :
Why it is written that "copy constructor copies *p into item"? I mean, item is direct initialized. If we would have written Sales_data item = *p; then it will be called copy initialized, so why they have written copy constructor copies *p into item in the comment.
Now, to verify this for myself, i tried creating a simple example myself, but there also i am unable to understand the concept properly. My custom example is as follows:
#include<iostream>
#include<string>
class MAINCLASS{
private:
std::string name;
int age =0;
public:
MAINCLASS(){
std::cout<<"This is default initialization"<<std::endl;
}
MAINCLASS(MAINCLASS &obj){
std::cout<<"This is direct initialization"<<std::endl;
}
MAINCLASS(const MAINCLASS &obj):name(obj.name),age(obj.age){
std::cout<<"This is copy initialization"<<std::endl;
}
};
int main(){
MAINCLASS objectone;
MAINCLASS objecttwo =objectone;
MAINCLASS objectthree(objectone);
return 0;
}
Now when i run this program, i get the following output:
This is defalut initialization
This is direct initialization
This is direct initialization
My question from this program is as follws:
Why are we not getting the output "this is copy initialization" in the second case when i write MAINCLASS objecttwo =objectone;? I have read that in direct initialization function matching is used and in copy constructor , we copy the right hand operand members into left hand operand members. So when i write MAINCLASS objecttwo =objectone; it should call the copy constructor and print "this is copy initialization" on the screen. But instead it is direct initializing the object. What is happening here?
Despite the poor choice of name, copy initialization is orthogonal to copy constructors.
A copy constructor is any constructor whose first parameter is a lvalue reference to its class type, and can be called with just one argument. It's just a constructor that can initialize new objects from existing objects. That's pretty much all there is to it. Both the constructors you declared are in fact copy constructors. This one would be too
MAINCLASS(MAINCLASS volatile &obj, void *cookie = nullptr) {
// .. Do something
// This is a copy c'tor since this is valid:
// MAINCLASS volatile vo;
// MAINCLASS copy1_vo(vo);
}
And as the other answers noted copy initialization is simply the name for a family of initialization contexts. It includes initialization involving =, passing arguments to functions, return statements and throw expressions (and I'm probably forgetting something). Direct initialization involves other contexts.
A copy constructor can be used in any of the above. Be it copy initialization or direct initialization. The difference between the two - as appertains to constructors - is how an overload set of constructors is built. Copy initialization doesn't make use of constructors declared explicit. For instance, in this example
struct Example {
Example() = default;
explicit Example(Example const&) {}
};
int main() {
Example e;
Example e1(e); // Okay, direct initialization
Example e2 = e1; // Error! Copy initialization doesn't make use of explicit constructor
}
Even though we have a copy constructor, it can't be called in a copy-initialization context!
As far as the unexpected print out of your program, it's simply a matter of overload resolution choosing a more matching function. Your origin object is not declared const. So binding it to a non-const lvalue reference is simply the preferred choice in overload resolution.
Don't confuse copy construction and copy initialisation. You can copy-construct using direct or copy initialisation.
Copy initialisation refers to a set of initialisation syntax and semantics. This includes the T a = b syntax.
The copy constructor is a special class method that takes an argument of said class. This method should only take one parameter (both T& or const T& will do). Copy construction occurs when that function is called.
With this in mind, we can go on to answer your questions.
Why it is written that "copy constructor copies *p into item"? I mean, item is direct initialized. If we would have written Sales_data item = *p; then it will be called copy initialized...
Both Sales_data item = *p and Sales_data item(*p) call the copy constructor. But, the former uses copy initialisation (T a = b), whereas the latter uses direct initialisation (T a(b)).
Why are we not getting the output "this is copy initialization" in the second case when i write MAINCLASS objecttwo =objectone;?
Actually, the issue here isn't whether it's copy/direct initialised. This is an issue of lvalue/rvalue overload resolution.
Consider the following program:
#include <iostream>
void f(int& i) { std::cout << "int&\n"; }
void f(const int& i) { std::cout << "const int&\n"; }
int main() {
f(1); // f(const int&)
int i = 2;
f(i); // f(int&)
}
f is chosen based on whether the value passed is lvalue or rvalue. In the first case, 1 is an rvalue, so f(const int&) is called (see this). In the second case, i is an lvalue, and f(int&) is chosen since it's more general.
So in your case, both MAINCLASS objecttwo =objectone; and MAINCLASS objectthree(objectone); call the copy constructor. And again, the former uses copy initialisation, whereas the latter uses direct initialisation. It's just that both of these calls choose the non-const ref overload instead: MAINCLASS(MAINCLASS&).
Copy initialization and direct initialization is based on the syntax used to construct.
See Confusion in copy initialization and direct initialization.
Which constructor gets invoked is based on overload resolution (and not the syntax to construct)
The compiler invokes the function which best matches the passed arguments to the defined parameters.
In your example since objectone is non-const, the best match is the copy constructor with a non-const parameter. Since the other copy constructor has a const& parameter, it will get invoked for a const object.
Rewriting your example:
#include<iostream>
#include<string>
class MAINCLASS {
private:
std::string name;
int age = 0;
public:
MAINCLASS() {
std::cout << "This is default initialization" << std::endl;
}
MAINCLASS(MAINCLASS& obj) {
std::cout << "This is copy constructor with non-const reference parameter" << std::endl;
}
MAINCLASS(const MAINCLASS& obj) :name(obj.name), age(obj.age) {
std::cout << "This is copy constructor with const reference parameter" << std::endl;
}
};
int main() {
MAINCLASS objectone;
const MAINCLASS const_objectone;
MAINCLASS objecttwo = objectone; // copy initialization of non-const object
MAINCLASS objectthree(objectone); // direct initialization of non-const object
MAINCLASS objectfour = const_objectone; // copy initialization of const object
MAINCLASS objectfive(const_objectone); // direct initialization of const object
return 0;
}
The output would be:
This is default initialization
This is default initialization
This is copy constructor with non-const reference parameter
This is copy constructor with non-const reference parameter
This is copy constructor with const reference parameter
This is copy constructor with const reference parameter

Adding functionality to a default copy constructor [duplicate]

This question already has answers here:
How can I extend a compiler generated copy constructor
(5 answers)
Closed 5 years ago.
I have a question. Say I have a class A, for which I'm perfectly happy with the default copy constructor.
Can I add functionality to this default copy constructor without re-writing all its work again?
Trivial example:
class A
{
public:
A(int n) : data(n) { };
private:
int data;
};
Suppose I want to print the message "Copy constructor!" each time a copy constructor is called. For this simple case I would just write my own copy constructor, which takes charge of the shallow copy explicitly, and also prints out the message. Is there a way to add the message printing (or whatever other functionality I want) on top of the default copy constructor, without writing explictly the shallow coyp?
Suppose I want to print the message "Copy constructor!" each time a copy constructor is called. For this simple case I would just write my own copy constructor, which takes charge of the shallow copy explicitly, and also prints out the message.
Yes, you need to provide your copy constructor explicitely and add that printing out the message.
class A
{
public:
A(int n) : data(n) { };
// You need to add tis:
A(const& A rhs) : data(rhs.data) {
std::cout << "Copy constructor!" << '\n';
}
private:
int data;
};
Is there a way to add the message printing (or whatever other functionality I want) on top of the default copy constructor, without writing explictly the shallow coyp?
No, there isn't.

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.

What is a copy constructor in C++?

On page 6 of Scott Meyers's Effective C++, the term 'copy constructor' is defined. I've been using Schiltdt's book as my reference and I can find no mention of copy constructors. I get the idea but is this a standard part of c++? Will such constructors get called when a pass a class by value?
Yes, copy constructors are certainly an essential part of standard C++. Read more about them (and other constructors) here (C++ FAQ).
If you have a C++ book that doesn't teach about copy constructors, throw it away. It's a bad book.
A copy constructor has the following form:
class example
{
example(const example&)
{
// this is the copy constructor
}
}
The following example shows where it is called.
void foo(example x);
int main(void)
{
example x1; //normal ctor
example x2 = x1; // copy ctor
example x3(x2); // copy ctor
foo(x1); // calls the copy ctor to copy the argument for foo
}
See Copy constructor on Wikipedia.
The basic idea is copy constructors instantiate new instances by copying existing ones:
class Foo {
public:
Foo(); // default constructor
Foo(const Foo& foo); // copy constructor
// ...
};
Given an instance foo, invoke the copy constructor with
Foo bar(foo);
or
Foo bar = foo;
The Standard Template Library's containers require objects to be copyable and assignable, so if you want to use std::vector<YourClass>, be sure to have define an appropriate copy constructor and operator= if the compiler-generated defaults don't make sense.
Copy constructor will be called in then following scenarios:
When creating new objects from an existing object.
MyClass Obj1;
MyClass Obj2 = Obj1; // Here assigning Obj1 to newly created Obj2
or
MyClass Obj1;
MyClass Obj2(Obj1);
When passing class object by value.
void NewClass::TestFunction( MyClass inputObject_i )
{
// Function body
}
Above MyClass object passed by value. So copy constructor of MyClass will call. Pass by reference to avoid copy constructor calling.
When returning objects by value
MyClass NewClass::Get()
{
return ObjMyClass;
}
Above MyClass is returned by value, So copy constructor of MyClass will call. Pass by reference to avoid copy constructor calling.
The C++ FAQ link posted by Eli is nice and gbacon's post is correct.
To explicitly answer the second part of your question: yes, when you pass an object instance by value the copy constructor will be used to create the local instance of the object in the scope of the function call. Every object has a "default copy constructor" (gbacon alludes to this as the "compiler generated default") which simply copies each object member - this may not be what you want if your object instances contain pointers or references, for example.
Regarding good books for (re)learning C++ - I first learned it almost two decades ago and it has changed a good deal since then - I recommend Bruce Eckel's "Thinking in C++" versions 1 and 2, freely available here (in both PDF and HTML form):
http://www.ibiblio.org/pub/docs/books/eckel/
Copy Constructor is an essential part of C++. Even-though any C++ compiler provides default copy constructor if at all if we don't define it explicitly in the class, We write copy constructor for the class for the following two reasons.
If there is any dynamic memory allocation in the class.
If we use pointer variables inside the class. (otherwise it will be a shallow copy in
which 2 objects will point to the same memory location.)
To make a deep copy, you must write a copy constructor and overload the assignment operator, otherwise the copy will point to the original, with disastrous consequences.
The copy constructor syntax would be written as below:
class Sample{
public:
Sample (const Sample &sample);
};
int main()
{
Sample s1;
Sample s2 = s1; // Will invoke Copy Constructor.
Sample s3(s1); //This will also invoke copy constructor.
return 0;
}
A copy constructor is a constructor which does deep copy. You should write your own copy constructor when there is a pointer type variable inside the class. Compiler will insert copy constructor automatically when there is no explicit copy constructor written inside the code. The type of a copy constructor parameter should always be reference type, this to avoid infinite recursion due to the pass by value type.
below program explains the use of copy constructor
#include <iostream>
#pragma warning(disable : 4996)
using namespace std;
class SampleTest {
private:
char* name;
int age;
public:
SampleTest(char *name1, int age) {
int l = strlen(name1);
name = new char[l + 1];
strcpy(this->name, name1);
this->age = age;
}
SampleTest(const SampleTest& s) { //copy constructor
int l = strlen(s.name);
name = new char[l + 1];
strcpy(this->name, s.name);
this->age = s.age;
}
void displayDetails() {
cout << "Name is " << this->name << endl;
cout << "Age is " << this->age << endl;
}
void changeName(char* newName) {
int l = strlen(newName);
name = new char[l + 1];
strcpy(this->name, newName);
}
};
int main() {
SampleTest s("Test", 10);
s.displayDetails();
SampleTest s1(s);
cout << "From copy constructor" << endl;
s1.displayDetails();
s1.changeName("Test1");
cout << "after changing name s1:";
s1.displayDetails();
s.displayDetails();
cin.get();
return 0;
}

C++ constructor syntax [duplicate]

This question already has answers here:
Is there a difference between copy initialization and direct initialization?
(9 answers)
Closed 1 year ago.
Simple question: are the following statements equivalent? or is the second one doing more implicit things behind the scenes (if so, what?)
myClass x(3);
myClass x = myClass(3);
Thanks!
They are not completely identical. The first is called "direct initialization" while the second is called "copy initialization".
Now, the Standard makes up two rules. The first is for direct initialization and for copy initialization where the initializer is of the type of the initialized object. The second rule is for copy initialization in other cases.
So, from that point of view both are termed in one - the first - rule. In the case where you have copy initialization with the same type, the compiler is allowed to elide a copy, so it can construct the temporary you create directly into the initialized object. So you can end up very well with the same code generated. But the copy constructor, even if the copy is elided (optimized out), must still be available. I.e if you have a private copy constructor, that code is invalid if the code in which it appears has no access to it.
The second is called copy-initialization, because if the type of the initializer is of a different type, a temporary object is created in trying to implicitly convert the right side to the left side:
myclass c = 3;
The compiler creates a temporary object of the type of myclass then when there is a constructor that takes an int. Then it initializes the object with that temporary. Also in this case, the temporary created can be created directly in the initialized object. You can follow these steps by printing messages in constructors / destructors of your class and using the option -fno-elide-constructors for GCC. It does not try to elide copies then.
On a side-note, that code above has nothing to do with an assignment operator. In both cases, what happens is an initialization.
The second one may or may not call for an extra myclass object construction if copy elision is not implemented by your compiler. However, most constructors, have copy elision turned on by default even without any optimization switch.
Note initialization while construction never ever calls the assignment operator.
Always, keep in mind:
assignment: an already present object gets a new value
initialization: a new object gets a value at the moment it is born.
In the second one, a temporary object is created first and then is copied into the object x using myClass's copy constructor. Hence both are not the same.
I wrote the following to try and illustrate understand what's going on:
#include <iostream>
using namespace std;
class myClass
{
public:
myClass(int x)
{
this -> x = x;
cout << "int constructor called with value x = " << x << endl;
}
myClass(const myClass& mc)
{
cout << "copy constructor called with value = " << mc.x << endl;
x = mc.x;
}
myClass & operator = (const myClass & that)
{
cout << "assignment called" << endl;
if(this != &that)
{
x = that.x;
}
return *this;
}
private:
int x;
};
int main()
{
myClass x(3);
myClass y = myClass(3);
}
When I compile and run this code I get the following output:
$ ./a.out
int constructor called with value x = 3
int constructor called with value x = 3
This would seem to indicate that there is no difference between the two calls made in the main function, but that would be wrong. As litb pointed out, the copy constructor must be available for this code to work, even though it gets elided in this case. To prove that, just move the copy constructor in the code above to the private section of the class definition. You should see the following error:
$ g++ myClass.cpp
myClass.cpp: In function ‘int main()’:
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private
myClass.cpp:37: error: within this context
Also note that the assignment operator is never called.