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;
}
Related
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 11 months ago.
class person
{
private:
string p_name;
int p_age;
public:
person(string name, int age){
p_name = name;
p_age = age;
}
person(const person &pers){
p_name = pers.p_name;
p_age = pers.p_age;
}
void print(){
cout << "Name: " << p_name << '\n';
cout << "Age: " << p_age << '\n';
cout << &p_age << '\n';
cout << '\n';
}
};
int main()
{
person obj1{"Name", 18};
obj1.print();
person obj2{obj1};
obj2.print();
return 0;
}
Here's my code, it works, but when i delete copy constructor in still works, so what is a point to use copy constructor?
In this example, there is absolutely no use. C++ automatically generates a copy constructor that does exactly what you just do here: Copies each constituent field.
You need to implement a copy constructor (and several other things) if your class is managing resources in some unusual way. Your person class is nice: It stores an int and a string by value, which is super predictable, so C++ does the right thing automatically. If you were storing raw pointers (say, an int*) then you'd need a copy constructor, as well as a copy assignment, move assignment, move constructor, and destructor.
But in modern C++, we try to avoid that. Instead of raw pointers, use references (int&) for borrowing data, unique pointers (std::unique_ptr<int>) for owning data, and shared pointers (std::shared_pointer<int>) for that rare situation where you need multi-ownership, and save raw pointers and custom Rule of Five methods for that incredibly rare situation where all of the above fail you.
when i delete copy constructor in still works
You're not deleting the copy constructor. You're just not providing a user-defined copy constructor. Note that there is a difference between "deleting a copy ctor" and "not providing one". In the latter case, the compiler will synthesize the copy constructor for you.
That synthesized copy constructor, memberwise-copies the data members of its argument into the object being created. This means that the copy ctor that will be synthesized for your class person, will just copy(initialize) both of the data members p_name and p_age from the passed argument similar to what you were doing manually. Note that the synthesized copy ctor will intialize the data members instead of assigning values to them from the passed argument. For example, the synthesized copy ctor for your class person will be equivalent to:
person(const person& rhs): p_name(rhs.p_name), p_age(rhs.p_age)
{
}
what is a point to use copy constructor?
As i said, the synthesize copy ctor just memberwise copies the data members of the passed argument into the object being created. But sometimes we want to customize this behavior. That is, sometimes we want that the copy ctor will do something specific to our needs, for which we provide the user defined copy ctor. One example is when our class is managing resources in ways that the synthesized copy ctor will not be able to.
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
The book I'm reading says that when your class contains a member that's a reference or a const, using the compiler-generated copy constructor or assignment operators won't work. For instance,
#include <iostream>
#include <string>
using namespace std;
class TextBlock
{
public:
TextBlock (string str) : s(str) {
cout << "Constructor is being called" << endl;
}
string& s;
};
int main () {
TextBlock p("foo");
TextBlock q(p);
q = p;
cout << "Q's s is " << q.s << endl;
return(0);
}
According to my book, both the lines TextBlock q(p); and q = p; should return compiler errors. But using the g++ compiler for Linux, I'm only getting an error for the line q = p; When I comment that out, this works fine and the code compiles. The correct s is output for Q, so it's apparently being copied by the compiler-generated copy constructor. I get the same results when I change the line string& s; to const string s.
Have there been some changes to C++ that now allow the copy constructor to be generated automatically for reference and const objects, but not the assignment operator? Or maybe I'm just not understanding the book correctly? Any thoughts?
The book is wrong. A const member or a reference member will
inhibit generation of the default copy assignment operator, but
doesn't prevent the compiler from generating a copy constructor.
Don't try to learn a special rule here.
The compiler-generated default versions of special member functions follow a simple pattern:
The type-appropriate special member function is called for every subobject (base classes and members).
From that, you can work out every case.
int i;
int &ri1 = i;
int &ri2 = ri1;
is allowed, so copying an object containing an int& is allowed.
There is no assignment operator for references (ri2 = ri1; does not rebind the reference), so assignment is not allowed.
References can't be default constructed:
int& ri; // error
so a type containing int& can't be default-constructed.
An important consideration is that the access checks are done for compiler-defaulted code just as if you had written it yourself. So interesting things can happen if a base class has, for example, a private copy constructor... and you don't have to learn special rules for any of them.
Q1: Does the "self class typed pointer constructor" have a decent/official name?
Q2: Why is copy constructor much more famous than "self class typed pointer constructor"?
Or what are the cases that we must use copy constructor rather then "self class typed pointer constructor"?
class MyClass
{
public:
int i;
MyClass()
{
i = 20;
}
//Copy constructor
MyClass(MyClass const & arg)
{
i = arg.i;
}
//What kind of Constructor is this one?
MyClass(MyClass* pArg)
{
i = pArg->i;
}
};
int main() {
MyClass obj;
MyClass* p = new MyClass();
//call copy constructor
MyClass newObj(obj); //call copy constructor directly
MyClass newObj2(*p); //dereference pointer and then call copy constructor
MyClass* pNew = new MyClass(*p); //dereference pointer and then call copy constructor
//Call THE constructor
MyClass theObj(&obj); //get the address, call THE constructor
MyClass theObj2(p); //call pointer constructor directly
MyClass* ptheNew = new MyClass(p); //call pointer constructor directly
}
It has no special name, because there is nothing special about it.
The copy constructor is "more famous", because it is special. It is special because it is a fundamental part of the way the language works. If you don't declare a copy constructor, in most classes, one will be implicitly defined for you. It is involved in many basic operations, such as these:
void foo(MyClass obj) // the copy ctor is (potentially) called to create this parameter
{
...
}
MyClass bar() // the copy ctor is (potentially) called when this function returns, and when it result is used
{
...
}
MyClass a;
MyClass b(a); // This calls the copy constructor
MyClass c = b; // So does this
Note that, in many cases, the copy is optimized away. See Copy Elision. Also, in C++11, the move constructor is called in many places where the copy constructor used to be called. But the move constructor too can be optimized away in the same places that copy elision could happen.
I can't think of many reasons you would ever use "THE constructor", as you call it.
On a side note, a copy constructor should almost always have this signature:
MyClass(MyClass const &)
Not this one:
MyClass(MyClass &)
To an object in C++, we usually use reference rather than pointer. We can use reference to get the address of the object, and than you can use '.' to access its method or data, it is more simple and direct than '->'.
I think there is no need to use 'THE constructor'.
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.