Why should i use copy constructor? [duplicate] - c++

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.

Related

In which cases does cpp create a default copy constructor [duplicate]

This question already has answers here:
Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?
(3 answers)
Closed 2 months ago.
I am confused why this doesn't show an error because a copy of b is created but there is no copy constructor - struct A (line B c{b}; )
Did C++ create the copy constructor or is it something else in question? Thanks
#include <iostream>
using namespace std;
struct B{
int a = 0;
B(){cout << "3" << endl;}
~B(){cout << "5" << endl;}
};
struct A{
B b;
B c{b};
A(int a){cout << "4" << endl;}
A(){cout << "1" << endl;}
~A(){cout << "2" << endl;}
};
void foo(A y){
cout << "6" << endl;
}
void foo2(A& a){
cout << "7" << endl;
}
int main()
{
B a{};
A c{};
foo(2);
foo2(c);
return 0;
}`
From the documentation on copy constructors
If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class. This implicitly-declared copy constructor has the form T::T(const T&) if all of the following are true:
each direct and virtual base B of T has a copy constructor whose parameters are const B& or const volatile B&;
each non-static data member M of T of class type or array of class type has a copy constructor whose parameters are const M& or const volatile M&.
That is, C++ will create a copy constructor for you if it can (if each field can be copied) and if you haven't explicitly opted out or written one yourself.
You can opt out of a copy constructor (since C++11) with the delete keyword.
B(const B&) = delete;
This will forbid C++ from creating a copy constructor, even though you didn't define one.
In your case, B has no base classes, so the first bullet point does not apply. The only non-static member is of type int, which is not of class or array-of-class type and thus is trivial to copy.
It's very important to keep in mind that C++ will generate a copy constructor, even if it's not semantically correct to do so. For instance, if your class contains raw pointers, C++ is very likely to generate a copy constructor that does not do the right thing. That's because, for raw pointers, C++ doesn't understand Rule of Three/Five.
If your class owns a pointer, you should use std::unique_ptr (which has ownership semantics by default and will forbid copying, by the rules above). If your class shares ownership of a pointer, you should use std::shared_ptr, which will work correctly in the presence of a defaulted copy constructor. If your class borrows a pointer, you should consider using a reference type, and if that's not an option, you should clearly document your non-owning pointer and you should consider writing an explicit copy constructor if the default one doesn't satisfy Rule of Three/Five.
In your case, all you have is a (non-pointer) int, so the more complicated nuances don't come up. But if you keep learning C++, they will, so I recommend giving that Stack Overflow question a thorough read when you have the time.

Why C++ compiler does not delete copy constructor when class has reference member? [duplicate]

This question already has answers here:
Assignment operator and copy constructor in the presence of references
(5 answers)
Closed 3 years ago.
C++ compiler will not provide default copy assignment operator to a class which has reference member(and some other scenarios also).
Reason is, if default copy assignment operator is provided then both source and destination object's reference member refers to same copy.
However, default copy constructor is provided in same scenario and this introduces same problem as providing default copy assignment operator.
Any reason for providing default copy constructor?
#include <iostream>
using namespace std;
class People{
public:
People(string name = ""):m_name(name){
}
string getName(){
return m_name;
}
void setName(string name){
m_name = name;
}
private:
string& m_name;//reference member
};
int main() {
People a("Erik");
People b(a);
a.setName("Tom");
cout << a.getName() << endl;//This prints "Tom"
cout << b.getName() << endl;//This prints "Tom"
//a = b; //Build error
return 0;
}
A reference can be initialized, in the copy constructor, to refer to the same object as the reference in the other class instance. But once initialized, the reference cannot be reassigned to refer to a different object; so an assignment operator cannot maintain semantics similar to those of a copy constructor.
Your example binds m_name reference to the constructor's parameter, which goes out of scope when the constructor returns, leaving the reference dangling. Any use of m_name afterwards exhibits undefined behavior. You shouldn't be reaching any conclusions based on the behavior of this program.
Why C++ compiler does not delete copy constructor when class has reference member?
Because references are copyable.
If default copy assignment operator is provided then both source and destination object's reference member refers to same copy.
No. Implicit copy assignment operator cannot be provided because references cannot be assigned to refer to another object.

C++ copy constructor double call on member initialization

Consider the below code, where a composing class with another class as its member is being instantiated:
class CopyAble {
private:
int mem1;
public:
CopyAble(int n1) : mem1(n1) {
cout << "Inside the CopyAble constructor" << endl;
}
CopyAble(const CopyAble& obj) {
cout << "Inside the CopyAble copy constructor" << endl;
this->mem1 = obj.mem1;
return *this;
}
CopyAble& operator=(const CopyAble& obj) {
cout << "Inside the CopyAble assignment constructor" << endl;
this->mem1 = obj.mem1;
}
~CopyAble() {};
};
class CopyAbleComposer {
private:
CopyAble memObj;
public:
CopyAbleComposer(CopyAble m1) : memObj(m1) {
cout << "Composing the composer" << endl;
}
~CopyAbleComposer() {}
};
int main()
{
CopyAble ca(10);
CopyAbleComposer cac(ca);
return 0;
}
When I run this, I get the output:
Inside the CopyAble constructor
Inside the CopyAble copy constructor
Inside the CopyAble copy constructor
Composing the composer
Which means that the CopyAble copy constructor is being run twice - once when the CopyAble object is passed into the CopyAbleComposer constructor, and again when the initializer memObj(m1) runs.
Is this an idiomatic use of the copy constructor? It seems very inefficient that the copy constructor runs twice when we try to initialize a member object with a passed-in object of the same type, and it seems like a trap a lot of C++ programmers can easily fall into without realizing it.
EDIT: I don't think this is a duplicate of the question regarding passing a reference into the copy constructor. Here, we are being forced to pass a reference into a regular constructor to avoid duplicate object creation, my question was that is this generally known that class constructors in C++ should have objects passed in by reference to avoid this kind of duplicate copy?
You should accept CopyAble by reference at CopyAbleComposer(CopyAble m1), otherwise a copy constructor will be called to construct an argument. You should also mark it as explicit to avoid accidental invocations:
explicit CopyAbleComposer(const CopyAble & m1)
Pass-by-value and the associated copying is a pretty widely known property of C++. Actually, in the past C++ was criticized for this gratuitious copying, which happened silently, was hard to avoid and could lead to decreased performance. This is humorously mentioned e.g. here:
You accidentally create a dozen instances of yourself and shoot them all in the foot. Providing emergency medical assistance is impossible since you can't tell which are bitwise copies and which are just pointing at others and saying, "That's me, over there."
C++98
When any function/method is declared to receive an argument by value, this sort of copying happens. It doesn't matter if it's a constructor, a "stand-alone" function or a method. To avoid this, use a const reference:
CopyAbleComposer(const CopyAble& m1) : memObj(m1)
{
...
}
Note: even if you rearrange your code as below, one copy always remains. This has been a major deficiency in C++ for a long time.
CopyAbleComposer cac(CopyAble(10)); // initializing mem1 by a temporary object
C++11
C++11 introduced move semantics, which replaces the additional copy by a "move" operation, which is supposed to be more efficient than copy: in the common case where an object allocates memory dynamically, "move" only reassigns some pointers, while "copy" allocates and deallocates memory.
To benefit from optimization offered by move semantics, you should undo the "optimization" you maybe did for C++98, and pass arguments by value. In addition, when initializing the mem1 member, you should invoke the move constructor:
CopyAbleComposer(CopyAble m1) : memObj(std::move(m1)) {
cout << "Composing the composer" << endl;
}
Finally, you should implement the move constructor:
CopyAble(CopyAble&& obj) {
cout << "Inside the CopyAble move constructor" << endl;
this->mem1 = obj.mem1;
}
Then you should see that the "copy" message doesn't appear, and is replaced by the "move" message.
See this question for more details.
Note: In all these examples, the CopyAble objects are assumed to be much more complex, with copy and move constructors doing non-trivial work (typically, resource management). In modern C++, resource management is considered a separate concern, in the context of separation of concerns. That is, any class that needs a non-default copy or move constructor, should be as small as possible. This is also called the Rule of Zero.

Why is the copy constructor of the string used?

I have the following code:
class TestClass
{
public:
TestClass(){};
std::string GetTestString()
{
return (mTestString);
}
void SetTestString(const std::string& rTestString)
{
mTestString = rTestString;
}
private:
std::string mTestString;
};
TestClass* pGlobalVar;
void SomeFunction(TestClass MyClass)
{
pGlobalVar->SetTestString("cba");
std::cout << "Changed string: " << pGlobalVar->GetTestString() << std::endl;
std::cout << "Copied string: " << MyClass.GetTestString() << std::endl;
}
int main()
{
pGlobalVar = new TestClass();
pGlobalVar->SetTestString("abc");
std::cout << "Original string: " << pGlobalVar->GetTestString() << std::endl;
SomeFunction(*pGlobalVar);
delete (pGlobalVar);
}
This outputs the following:
Original string: abc
Changed string: cba
Copied string: abc
As I did not define a copy constructor for my class, I would expect that a flat copy would be made, including the pointer in the std::string. Apparently though the std::string copy constructor is used, since a change to the original string did not change the copy.
Can anyone explain to me why it did not make flat copy?
I'm using Linux with GCC 4.4.6.
As I did not define a copy constructor for my class, I would expect that a flat copy would be made
Since you didn’t define a copy constructor, C++ did for you.
The auto-generated copy constructor calls the constructor for all its member variables (if they have one).
Analogously, auto-generated constructors call all their members’ constructors, and destructors call all their members’ destructors.
As I did not define a copy constructor for my class, I would expect that a flat copy would be made, including the pointer in the std::string.
No, the implicitly generated copy-constructor will copy each data member (and base subobject) using its copy constructor if it has one.
Can anyone explain to me why it did not make flat copy?
Because that would be horribly broken. A class defines a copy constructor because it has to be copied in a certain way; in the case of std::string, it has to create a new buffer. If the new string simply held a copy of the other's pointer, then both would think they owned the same buffer, and both would try to deallocate it when they were destroyed.

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;
}