references and pointers in the context of C++ classes - c++

I would like to ask a question about references and pointers in C++.
I am a beginner in C++ so I apologise for if the answer is trivial.
I have written the following code as part of a tutorial.
#include <iostream>
using namespace std;
class Deep {
private:
int *data;
public:
void set_data_value(int d) {*data = d;}
int get_data_value () {return *data;}
// Constructor
Deep (int d);
// Copy constructor
Deep (const Deep &source);
// Destructor
~Deep();
};
Deep::Deep(int d) {
data = new int;
*data = d;
}
Deep::Deep (const Deep &source)
: Deep (*source.data){ // main body of the constructor (delegation comes before the body)
cout << "Copy Constructor - deep copy" << endl;
}
Deep::~Deep() {
delete data;
cout << "Destructor deleting data" << endl;
}
void display_deep (Deep s) {
cout << s.get_data_value() << endl;
}
int main () {
Deep obj1 {100};
display_deep (obj1);
Deep obj2{obj1};
obj2.set_data_value(1000);
cout << endl;
return 0;
}
This code works. I will explain what I have done:
I defined a class named Deep to practice a deep copy. The pointer named data is private and I've included (and later defined) the function prototypes set_data_value and get_data_value.
set_data_value takes in an integer d, dereferences data and assigns the value d to it.
get_data_value simply returns the dereferenced value of data.
In the public domain also there is a constructor that accepts one integer d, a copy constructor which keeps the object constant and takes in a reference &source alongside a destructor.
Inside the copy constructor, I use a delegation constructor to improve the flow of the code.
However, if we observe the copy constructor
Deep::Deep (const Deep &source)
: Deep (*source.data){ // main body of the constructor (delegation comes before the body)
cout << "Copy Constructor - deep copy" << endl;
}
we know that this is run upon the pass-by-value nature of void display_deep (Deep s), so source is a reference to our s passed in. We then point to source and somehow obtain the value of data, which is then passed to the constructor.
How does this work? Does *source.data work as I described or does the compiler take a different route?

We then point to source and
There is no pointing to anything. In this line:
: Deep (*source.data)
You are just accessing the data inside source. Then you are dereferencing it. Just like you dereference *data to get the value inside it.

Related

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.

Why was copy constructor called in this example?

I am very new to C++ and I don't understand why the copy constructor was called in the following code:
#include <iostream>
using namespace std;
class Line
{
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main( )
{
Line line(10);
display(line);
return 0;
}
And when it runs:
Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!
Why does it construct an other Line object after the first one with the simple constructor?
Thanks!
because you are passing Line as value
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
You should pass it as constant reference, which is faster (and display shoud be a constant method so constant objects can call it).
void display(const Line &obj) const
{
cout << "Length of line : " << obj.getLength() <<endl;
}
(provided that you change to int getLength( void ) const;)
And in your case, think of redefining assignment operator
Line &operator=(const Line &other);
or affecting a line in another will copy pointer data and will crash on your second object deletion since memory will be freed twice.
If you want to make sure that default copy constructor / assignment operator cannot be called, just declare them in your private part:
private:
Line &operator=(const Line &other);
Line(const Line &other);
code trying to use them won't compile.
Your display function takes a Line by value - meaning the function gets its own copy. If you don't want that, pass by (const) reference or pointer instead.
The answer is here:
void display(Line obj) { ...
The argument of the function obj is passed by value.
So when the function is called a copy of the argument passed by the caller function is done.
In order to give you a trivial explanation, imagine:
function:main (caller) ->
make a copy of line ->
call the function display (callee) which is going to use the copy made by caller.
That policy is used in various case, for example:
To be sure that the callee function will does any effect (side-effect) on the variables of the caller.
When the callee function will perform a copy of the object, so you can avoid to make a copy inside the body function.
Because passing an argument by value will perform a copy of the argument itself, it is preferable using argument passed by reference.
This is an example:
void display(Line& obj) { ...
In that case it will not performed a copy of the object but the argument obj will be a reference (like a pointer) to the argument passed by the caller function.
In conclusion, passing by reference allows to callee function side effect, in other words the callee function can modify variables "owned" by caller function.
Copy constructors are called in following cases:
(a) when a function returns an object of that
class by value
(b) when the object of that class is passed by
value as an argument to a function
(c) when you construct an object based on another
object of the same class
(d) When compiler generates a temporary object and is initialized with a class object.
And in your code you are passing the object of that clas by value as an argument to a function
Hope this Helps

How this code runs without overloading for the assignment operator

I wonder how this code run specifically line 54 (line2 = line1) although there is no overloading for the assignment operator ?
It seems from the output that neither the copy constructor nor the normal constructor were called and surprisingly it gets output as expected 199 199
#include <iostream>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr;
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // How this is executed ??!
cout << line1.getLength() << " " << line2.getLength() << endl ;
/*display(line1);
display(line2);*/
cin.get();
return 0;
}
What you have there is undefined behavior. You assign line2 = line1 but have no user-defined assignment operator, so you use the default one provided by the compiler. And the default one simply copies all the fields, which in your case includes an int*. That gives you two copies of the same int*, leaks the value that line2 previously pointed to, and eventually double-deletes the one line1 originally pointed to. The second delete of the same pointer, which occurs when line1 goes out of scope at the end of main(), invokes undefined behavior.
If you have a destructor which frees resources, you probably need an assignment operator too. See the Rule of Three: http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
But the best solution is to stop using raw pointers. Use a smart pointer and this problem will not occur in the first place, and you can omit your destructor.
In a situation like this, writing your own copy constructor, assignment operator and destructor should be your last resort, not your first reaction.
Your first reaction should usually be to use some pre-defined class that already handles these chores for you. In this case, changing from a raw pointer to a shared_ptr (for only one possibility) cleans up the code fairly quickly. Using it, the code ends up something like this:
#include <iostream>
#include <memory>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
~Line(); // destructor
// copy constructor removed, because the one supplied by the
// compiler will be fine. Likewise the compiler-generated assignment
// operator.
private:
shared_ptr<int> ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// Note the use of make_shared instead of a raw `new`
ptr = make_shared<int>(len);
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
// don't need to actually do anything--freeing is automatic
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // uses compiler-generated assignment operator (which works)
cout << line1.getLength() << " " << line2.getLength() << endl ;
display(line1);
display(line2);
cin.get();
return 0;
}
Depending upon the situation, a unique_ptr might be a better fit than a shared_ptr. In this case, shared_ptr is probably easier to incorporate into the existing code though.
You might also want to read R. Martinho Fernandes' Rule of Zero blog post on this subject.
If no user-defined copy assignment operators are provided for a class type (struct, class, or union), the compiler will always declare one as an inline public member of the class.
This implicitly-declared copy assignment operator has the form T& T::operator=(const T&) if all of the following is true:
Each direct base B of T has a copy assignment operator whose parameters are B or 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 assignment operator whose parameters are M or const M& or const volatile M&
Otherwise the implicitly-declared copy assignment operator is declared as T& T::operator=(T&). (Note that due to these rules, the implicitly-declared copy assignment operator cannot bind to a volatile lvalue argument)
Copied from this article from CPPReference.

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