shallow copy vs deep copy

A shallow copy of an object copies all of the member field values. This works well if the fields are values, but may not be what you want for fields that point to dynamically allocated memory. The pointer will be copied. but the memory it points to will not be copied -- the field in both the original object and the copy will then point to the same dynamically allocated memory, which is not usually what you want. The default copy constructor and assignment operator make shallow copies.

A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by the fields. To make a deep copy, you must write a copy constructor or overload the assignment operator.


If an object has pointers to dynamically allocated memory, and the dynamically allocated memory needs to be copied when the original object is copied, then a deep copy is required.


Example:
class A
{
int i;
public:
A()
{
i=0;
}
void Set()
{
i=20;
}
void display()
{

cout < <>

}

int main()
{
A a,b;
a.Set();//change i to 20
b=a;
b.display(); //this displays the value of i as 20
}
by default here the compiler generates the assignment operator for these objects.

object 'a' is copied into object 'b' . so object 'b' data member 'i' value will same as object 'a' data member 'i' value.

so the output of this program is 20. becoz object 'a' has changed the value of 'i' data member to 20.

what happens if the class A has a pointer *ptr whose memory is created dynamically.

class A

{

char *ptr;

public: A()

{

ptr=NULL;

}

void Set()

{
ptr=new char[5];
strcpy(ptr,"hai");

}

void display()
{
cout < <>

}

void erase()

{

delete []ptr;

}
};

int main()
{

A a;
a.Set();//change i to 20
A b;
b=a;
a.erase();
b.display(); //nothin will be displayed as the memory is erased by a;
system("pause");
return 0;

}

then if we copy object 'a' into object 'b'. pointer(ptr) of object 'a' will get copied to object 'b's ptr but not the value pointed by pointer ptr of object 'a'.

object 'b' s ptr and object 'a's ptr will be pointing to same memory. suppose if object 'a' deletes the its pointer, then the object 'b' will be pointing to the memory which is deleted by 'a' object, so object 'b's ptr will be dangling. I

n this case we go for deep copy. so whenever class has data members which are allocated memory dynamically then we should go for deep copy. deep copy copies the values pointed by pointers but not the pointers.

A class that requires deep copies will generally need:

i )a destructor to delete the dynamically allocated memory.
ii) a copy constructor to make a copy of the dynamically allocated memory.
iii) an overloaded assignment operator to make a copy of the dynamically allocated memory.

Example using the overloaded assignment operator

class A
{
char *ptr;
public: A()
{
ptr=NULL;
}
void Set()
{

ptr=new char[5];

strcpy(ptr,"hai");
}

void display()
{

cout < < ptr;

}
void operator = (const A& a)
{

if(this != &a)
{
ptr=new char[5];

strcpy(ptr,a.ptr);
}
}
void erase()
{
delete []ptr;
}
};
int main()
{
A a;
a.Set();
A b;
b=a;

//invokes overloaded = operator , so creates new memory for b.ptr instead of pointing to //same memory of a.ptr

a.erase();


b.display(); //this displays "hai" becoz memory is not destroyed

system("pause");
return 0;
}
Prev page



function overloading

  1. Allows more than one function to share the same name.
  2. Overloaded function must have a unique signature in either the number or types of their arguments.
  3. Relieves the user of a library from having to remember function names that perform identical actions.

    The return type of a function is ignored while determining overloaded instances

Signatures are different in either the types or number of their arguments.
These instances are considered to be overloaded.

int func(int,int);
int func(int,int,int);
double func(double,double);


The following attempt to overload Func_t() is erroneous.

void Func_1(int);
void Func_!(int&);
void Func_1(const int);

Argument matching rules.

1.Exact match and trivial conversions.
2.Match using promotions.
3.Match using standard conversions.
4.Match using user-defined conversions.

Rule 1. Exact match and trivial conversions
exact match scenario

void Disp(char);
void Disp(int);
void Disp(int&,char&);
void Disp(const char,const int);

int v = 13;
char c = ‘v’;
Disp(v); //will invoke Disp(int)
Disp( c ); //will invoke Disp(char)


Trivial conversions.
t to t&
t& to t
t[ ] to t*
t to const t
F(arg-list) to (*F)(arg-list)

void Disp(char);
void Disp(int);
void Disp(int&,char&);
void Disp(const char,const int);
int v = 13;
char c = ‘v’;
Disp(c,v); //will invoke Disp(const char , const int)
Disp(v,c); //will invoke Disp(int &, char&)

Rule 2. Match using promotions


A char, short int can be promoted to an int.
A float can be promoted to a double.
void Disp(int);
void Disp(double);
char c;
short int s;
float f;
Disp( c) ; // will invoke Disp(int)
Disp( s); // will invoke Disp(int)
Disp( f); // will invoke Disp( double)


Rule 3. Using standard conversion
Uses standard type conversion between one primitive type to another primitive type.
Possible loss of data due to conversion.
void Disp(double);
void Disp( void *);
int v;
char *s;
Disp(v); //Disp(double);
Disp(s); //Disp(void *);

GDB

GDB - Gnome debugger

Many developers may be fed up with fixing the logical errors in programs which causes core dump etc.

Gnome debugger(GDB) is useful to debug the C++ programs. Its used to analyse the core files also. core is the state of memory at specif time caused by program crash.

Lets see this program which causes core dump.

debugging Sample program with GDB
Note: all programs here assume that necessary header files are included.

#include"iostream"
using namespace std;
void func();
int main()
{

func();
return 1;
}
void func()
{
char *p;
strcpy(p,"hello,world");
cout < <>$g++ -g prog.cpp –o prog.o
$ ./prog.o
u will get output like this

Program received signal SIGSEGV, Segmentation fault core dumped .

Core file will be created as core.pid where pid is process id.
Suppose core.1431 gets created here

Note: If core file is not created then check core file size using

$ulimit –c
if it gives 0 , then core files cant be created. So increase the size by giving the

$ulimit –c unlimited

use the command $gdb 'prog_name' 'core_filename' .

here executable is prog.o

$gdb prog.o core.1431

Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
Cannot access memory at address 0xb7600744
#0 0xb743a9b6 in ?? ()

(gdb) run
Starting program: /home/edarav/plusplus/a.out
starting the func Program received signal SIGSEGV, Segmentation fault.0xb743a9b6 in strcpy () from /lib/tls/libc.so.6

the last few lines say that core dumped has come from strcpy in our code. we didnt allocated any space for char *p and we re trying to write into that memory. so the *p has to be initialised with enough memory.

Valgrind - memory leak and memory corruption detector

Valgrind tool is the memory mis management detector. it can detect

1) memory leaks
2) un initialised memory
3)Mismatched use of malloc/new/new [] vs free/delete/delete []
4) Overlapping src and dst pointers in memcpy() and related functions
5)reading or writing from/to pointers after deleting or freeing that pointer etc.

valgrind is wrapper of many tools. among them lets have a look at memcheck tool.

how to use valgrind ?

$valgrind --tool= tool_name --leakcheck= yes executable(ex: a.out)

by default the tool_name will be 'memcheck'


what is a memory leak?
when we allocate memory dynamically (at run time) , and if we dont free it after use, until the termination of program that memory cannot be re-gained. this is called memoy leak.

see the following program prog1.cpp which creates two pointers p and s at runtime on heap. we freed the memory pointed by p, but we didnt freed the memory pointed by s. so the memory pointed by s will not be re used until termination of program.

lets use the valgrind tool to detect the memory leak.



#include"iostream"
using namespace std;
int main()
{
char *p= new char[10];
delete []p;
char *s=new char[20];
return 1;
}

$g++ -g prog.cpp

$valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out

always the first column will be pid of your process.

==13993== Memcheck, a memory error detector.
==13993== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==13993== Using LibVEX rev 1732, a library for dynamic binary translation
.==13993== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==13993== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==13993== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==13993== For more details, rerun with: -v
==13993====
13993====
13993== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 17 from 1)
==13993== malloc/free: in use at exit: 20 bytes in 1 blocks
.==13993== malloc/free: 2 allocs, 1 frees, 30 bytes allocated.
==13993== For counts of detected errors, rerun with: -v
==13993== searching for pointers to 1 not-freed blocks.
==13993== checked 104,344 bytes.
==13993
====13993== 20 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13993== at 0x401B085: operator new[](unsigned) (vg_replace_malloc.c:195) ==13993== by 0x8048595: main (in /home/edarav/plusplus/a.out)
==13993
====13993== LEAK SUMMARY:
==13993== definitely lost: 20 bytes in 1 blocks.
==13993== possibly lost: 0 bytes in 0 blocks.
==13993== still reachable: 0 bytes in 0 blocks.
==13993== suppressed: 0 bytes in 0 blocks.

the bold lines in LEAK SUMMARY will give you how much memory was lost . here we lost 20 bytes.

In our c++ program above we allocated 20 bytes for char *s and we didnt free it. so the report shows those 20 bytes. like wise valgrind memcheck tool can also detect the un initialsed memory.

Common valgrind options

Option : --num-callers=number
Purpose : Determines the number of function calls (i.e. depth of stacktrace) to display as part of showing where an error occurs within a program. The default is a measly 4.

Option : --leak-check=yes
Purpose : Enabling leak checking has valgrind search for memory leaks (i.e. allocated memory that has not been released) when the program finished.

Option : --leak-resolution=high
Purpose : An option that should be used when doing leak checking since all other options result in confusing reports.

Option : --show-reachable=yes
Purpose : An option that makes leak checking more helpful by requesting that valgrind report whether pointers to unreleased blocks are still held by the program.

Option : -v
Purpose : Run in more verbose mode.

Option : -fno-inline
Purpose : An option for C++ programs which makes it easier to see the function-call chain.

Option : --gen-suppressions=yes
Purpose : A simple way to generate a suppressions file in order to facilitate ignoring certain errors in future runs of the same code.

Option : --skin=addrcheck
Purpose : (Note that the name of this option has become --tool and has become mandatory for the development release). This selects the specific tool of valgrind that will run. Memcheck (the only tool covered here) is the default.

Option : --logfile=file-basename
Purpose : Record all errors and warnings to file-basename.pidpid

classes

what is the size of this empty class?

class A
{
};

int main()
{
A a;
cout < < sizeof(a);

what is the size of class B here?

class A
{

};
class B:public A
{
};
int main()
{
B b;
cout< < sizeof(b) ; return 0; } the size of B is also a 1. even though B is inherited from class A , which doesnt have data members, class B size will be 1. similarly if any empty class say C, is inherited from empty class B, then the size of class C would be only 1 .

Next Page

Virtual functions

what is a virtual funtion? when it is used!!

C++ virtual function is a member function of a class, whose functionality can be over-ridden in its derived classes. The whole function body can be replaced with a new set of implementation in the derived class.Whenever a program has a C++ virtual function declared, a v-table is constructed for the class. when we wan to select anything based on context at run time then we go for virtual functions.

Example: if we have one GUI application where you scroll mouse over various elements like buttons,links,navigation bar.you want to display some properties when your mouse points to buttons and you want to display other properties when your mouse points to links. so here you want to display the things based on your mouse points to at run time. in these kind of applications we will use virtual functions. In this example we will make display function as virtual.we can see which behaviour is varying and lets make it virtual

what is call-mechanism in late binding?

The v-table consists of addresses to the virtual functions for classes and pointers to the functions from each of the objects of the derived class. Whenever there is a function call made to the c++ virtual function, the v-table is used to resolve to the function address. This is how the Dynamic binding happens during a virtual function call.

Can virtual functions have inline declarations ?

Generally, compilers can't inline a virtual function call if the it's resolved dynamically. Therefore, declaring a virtual member function inline might seem pointless. However, not every call of a virtual function is resolved dynamically; in some cases, the compiler can resolve the call statically, as if the function weren't virtual. In situations like these, the compiler can also inline the call.

For example:

class Base

{

public:

inline virtual int f()

{

return 0;

}

};

int main()

{

Base b;

b.f(); // resolved statically; call can be inlined

}

The invocation of f() is resolved statically because b is not a pointer or a reference. The compiler can also expand the call inline, thereby optimizing the code even further.

Can you Instantiate object for this class?

#include"iostream"

using namespace std;

class A

{

public:virtual ~A()=0

};

int main()

{

A *a=new A();

return 0;

}

NO. destructor is also a member function. here it is pure virtual so the VTABLE is in-complete. we cant create the objects for classes whose VTABLES are incomplete.

Which class member function f1() will be invoked. A or B?

#include"iostream"

using namespace std;

class A

{

public:

virtual void f1()

{

cout < < "this is A class f1()" ;

}

void f2()

{

f1();

}

};

class B:public A

{

public:void f1()

{

cout< < "this is B class f1()" ;

};

int main()

{

A *a=new B();

a->f2();

return 0;

}

Here using the base class ponter we are calling the f2() function which is not virtual. hence A::f2() will be called, but in that body we are calling f1 again which is virtual, so the derived class B::f1() will be invoked