Why is the copy constructor of the string used? - c++

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.

Related

Why should i use copy constructor? [duplicate]

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.

Copy constructor and dynamic memory

I am a beginner in programming and I am learning about copy constructors. From different sources I can see that copy constructors are useful if I want to "deep copy" a class object so the new object's pointer members will point to new memory locations.
My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?
My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.
#include "iostream"
class Cat
{
public:
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
class EmptyCat
{
public:
EmptyCat() {}
~EmptyCat() {}
EmptyCat(EmptyCat&obj) {}
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
class CopyCat
{
public:
CopyCat() {}
~CopyCat() {}
CopyCat(CopyCat&obj);
int GetAge() { return *itsAge; }
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
CopyCat::CopyCat(CopyCat & obj)
{
itsAge = new int;
*itsAge = obj.GetAge();
}
int main()
{
Cat Garfield;
Cat Kitty(Garfield);
std::cout << "Memory addresses for the objects' <itsAge> member:" << std::endl;
std::cout << "Garfield and Kitty (Class Cat):" << std::endl;
Garfield.GetMem();
Kitty.GetMem();
EmptyCat Meow;
EmptyCat Purr(Meow);
std::cout << std::endl << "Meow and Purr (Class EmptyCat):" << std::endl;
Meow.GetMem();
Purr.GetMem();
CopyCat Fluffy;
CopyCat Felix(Fluffy);
std::cout << std::endl << "Fluffy and Felix (Class CopyCat):" << std::endl;
Fluffy.GetMem();
Felix.GetMem();
system("pause");
return 0;
}
If I run the program I get this:
Memory addresses for the objects' <itsAge> member:
Garfield and Kitty (Class Cat):
00BBDA60
00BBDA60
Meow and Purr (Class EmptyCat):
00BB46A0
00BB8280
Fluffy and Felix (Class CopyCat):
00BB82B0
00BBE8A0
Press any key to continue . . .
Deep copying and shallow copying is rather a C concept, where you have only structures and raw pointers. A pointer can be owned, in which case the copy must be deep, or it can be shared, in which case the copy is shallow (and you have to be careful about freeing it if it's allocated with malloc).
In C++, new is now effectively deprecated. We have unique pointers, which are "owning pointers" and "shared pointers". However pointers are relatively rare. Array members of classes are std::vectors, string members are std::strings. And copies are automatically deep, (You use a reference if you want a shallow copy).
Pointers are held back for relatively unusual situations, like trees and graphs.
My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?
You don't get the same result. CopyCat allocates new memory and copies the value from the old class. The EmptyCat just allocates new memory, but does not copy the value.
My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.
In Cat you haven't declared a copy constructor, so the compiler will generate one when needed. The default copy constructor does a member-wise copy from the original. In your case, this will copy the pointer (so that it stores the same address as the original).
In the EmptyCat you have a user defined copy constructor. But as that one doesn't handle the pointer member, its default value will be used.
int * itsAge = new int;
This is what allocates a new int and gets you a different pointer value.
You are not getting the same behavior with and without an empty copy constructor. EmptyCat(EmptyCat& obj) { } does absolutely nothing.
CopyCat(CopyCat& obj) {
itsAge = new int;
*itsAge = obj.GetAge();
}
dynamically allocates a new int and assigns to it a value from the obj.

In C++'s rule of three, why does operator= not call copy ctor?

The following "minimal" example should show the use of rule of 3 (and a half).
#include <algorithm>
#include <iostream>
class C
{
std::string* str;
public:
C()
: str(new std::string("default constructed"))
{
std::cout << "std ctor called" << std::endl;
}
C(std::string* _str)
: str(_str)
{
std::cout << "string ctor called, "
<< "address:" << str << std::endl;
}
// copy ctor: does a hard copy of the string
C(const C& other)
: str(new std::string(*(other.str)))
{
std::cout << "copy ctor called" << std::endl;
}
friend void swap(C& c1, C& c2) {
using std::swap;
swap(c1.str, c2.str);
}
const C& operator=(C src) // rule of 3.5
{
using std::swap;
swap(*this, src);
std::cout << "operator= called" << std::endl;
return *this;
}
C get_new() {
return C(str);
}
void print_address() { std::cout << str << std::endl; }
};
int main()
{
C a, b;
a = b.get_new();
a.print_address();
return 0;
}
Compiled it like this (g++ version: 4.7.1):
g++ -Wall test.cpp -o test
Now, what should happen? I assumed that the line a = b.get_new(); would make a hard copy, i.e. allocate a new string. Reason: The operator=() takes its argument, as typical in this design pattern, per value, which invokes a copy ctor, which will make a deep copy. What really happened?
std ctor called
std ctor called
string ctor called, address:0x433d0b0
operator= called
0x433d0b0
The copy ctor was never being called, and thus, the copy was soft - both pointers were equal. Why is the copy ctor not being called?
The copies are being elided.
There's no copy because b.get_new(); is constructing its 'temporary' C object exactly in the location that ends up being the parameter for operator=. The compiler is able to manage this because everything is in a single translation unit so it has sufficient information to do such transformations.
You can eliminate construction elision in clang and gcc with the flag -fno-elide-constructors, and then the output will be like:
std ctor called
std ctor called
string ctor called, address:0x1b42070
copy ctor called
copy ctor called
operator= called
0x1b420f0
The first copy is eliminated by the Return Value Optimization. With RVO the function constructs the object that is eventually returned directly into the location where the return value should go.
I'm not sure that there's a special name for elision of the second copy. That's the copy from the return value of get_new() into the parameter for operator= ().
As I said before, eliding both copies together results in get_new() constructing its object directly into the space for the parameter to operator= ().
Note that both pointers being equal, as in:
std ctor called
std ctor called
string ctor called, address:0xc340d0
operator= called
0xc340d0
does not itself indicate an error, and this will not cause a double free; Because the copy was elided, there isn't an additional copy of that object retaining ownership over the allocated string, so there won't be an additional free.
However your code does contain an error unrelated to the rule of three: get_new() is passing a pointer to the object's own str member, and the explicit object it creates (at the line "string ctor called, address:0xc340d0" in the output) is taking ownership of the str object already managed by the original object (b). This means that b and the object created inside get_new() are both attempting to manage the same string and that will result in a double free (if the destructor were implemented).
To see this change the default constructor to display the str it creates:
C()
: str(new std::string("default constructed"))
{
std::cout << "std ctor called. Address: " << str << std::endl;
}
And now the output will be like:
std ctor called. Address: 0x1cdf010
std ctor called. Address: 0x1cdf070
string ctor called, address:0x1cdf070
operator= called
0x1cdf070
So there's no problem with the last two pointers printed being the same. The problem is with the second and third pointers being printed. Fixing get_new():
C get_new() {
return C(new std::string(*str));
}
changes the output to:
std ctor called. Address: 0xec3010
std ctor called. Address: 0xec3070
string ctor called, address:0xec30d0
operator= called
0xec30d0
and solves any potential problem with double frees.
C++ is allowed to optimize away copy construction in functions that are returning a class instance.
What happens in get_new is that the object freshly constructed from _str member is returned directly and it's then used as the source for the assignment. This is called "Return Value Optimization" (RVO).
Note that while the compiler is free to optimize away a copy construction still it's required to check that copy construction can be legally called. If for example instead of a member function you have a non-friend function returning and instance and the copy constructor is private then you would get a compiler error even if after making the function accessible the copy could end up optimized away.
It isn't exactly clear why you expect the copy ctor to be used. The get_new() function will not create a new copy of the C object when it returns the value. This is an optimization called Return Value Optimization, any C++ compiler implements it.

How to prove that Copy Constructor is mandatory

I Have just created a class with an integer variable and a pointer variable. After creating its object , I passed it to a function. Even after returning the function the program is not throwing the exception
#include"iostream"
using namespace std;
class A
{
public :
int i;
char *c;
void show();
};
void func(A obj);
int main()
{
A a;
a.i = 10;
a.c = "string";
cout << " Before Fun " << endl;
a.show();
cout << " Going To Call func " << endl;
func(a);
cout << " After func " << endl;
a.show();
return 0;
}
void A::show()
{
cout << " The valuses in Object are " << i << '\t' << c << endl;
}
void func(A aa)
{
cout << " The valuses in Object are " << aa.i << '\t' << aa.c << endl;
}
In The Func I am passing the object a (from main) and it would get copied in aa (stack of func). so after returning from the func if i call show ( the pointer c would be null of a), It would give me exception
But it is not happening . please help me to prove the requirement of copy constructor
Hide the copy constructor. That will cause a compilation error everywhere it is called implicitly.
class A
{
public :
int i;
char *c;
private:
A(const A& _other);
};
If no copy constructor is declared for an object, one is implicitly defined. This copy constructor copies each element of the object.
In your example, the call to func(a) will call this copy constructor, and so aa will be a copy of a (aa.i will be 10 and aa.c will point to the first element of "string").
If you are using C++11 you can do the following to remove the copy constructor
class A
{
public :
int i;
char *c;
void operator=(const A& _other) = delete;
A(const A& _other) = delete;
};
or even better:
class A : public NonCopyable // perhaps std:: or if you prefer boost, boost::
{
public :
int i;
char *c;
};
http://en.wikipedia.org/wiki/C++11#Explicitly_defaulted_and_deleted_special_member_functions
When you make a class, a null constructor and copy constructor exist implicitly.
So that is why it does not throw an exception.
However, if you define ANY constructor, you will then need to define others otherwise the rest of the constructors will be overwritten.
For example, you define a null constructor only. Then it will throw an exception. Because the implicitly defined copy constructor will be overridden.
This is one way of proving the need of a copy constructor.
An implicit copy constructor does exist if you do not define one explicitly. It is called in your func() function. A object is copied and assigned a value for its member i.
Result will be: that you do get with show() the value for i that you had before when calling func. This is with no surprise because you are not doing any assignment to members of A inside A.
Implicit copy constructor by the compiler provide member-wise copy. This is what you may need in most cases.
When is default constructor not sufficient ? you have pointer like members, and need a deep-copy of it. You don't want to copy the pointer (what copy constructor would do), but rather to have the object pointed to copied. But why do you need deep copy ? You don't want to copy the pointer (which is owned by any instance of the class), and end up calling twice destructor on the same pointer. From the second call to delete on this pointer, heap corruption ensues. You may also need copy constructor made explicit for shared_pointers.
Note that, for performance reasons, it is best pass object by const reference than by value.
In your case the copy constructor provided by compiler is present.
Modify your code and write a copy constructor as:
//Default and copy constructor
A()
{
i = 0;
c = NULL;
}
A(const A& _other)
{
cout<<"In copy cons"<<endl;
}
When you will modify the code as per above when func gets called then your own copy constructor gets called in this case you will get the junk values(can not predict)
And if you modify your copy constructor code as
A(const A& _other)
{
cout<<"In copy cons"<<endl;
i = _other.i;
c = new char [(strlen(_other.c) +1)];
strcpy(c,_other.c);
}
Now you can see the differnce in both outputs and the use of Copy constructor how and where it's used.

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