Learn C++
Saturday, August 9, 2014
Sunday, April 27, 2014
C++ 11 tuple
In C++ 11 standard library, tuple is introduced which can
hold values of heterogeneous data type in one object. It is also known as
extended pair. We can keep any number of values in tuple.
Let’s see following example to understand how to use tuple,
#include <tuple>
#include <iostream>
#include <string>
using namespace std;
int
main(int argc, char* argv[])
{
tuple<string,int,double,int> info("Pranit",27,25000,86);
return 0;
}
To use tuple we first need to include tuple (#include <tuple>) header file
in C++ code. We will be using cout
and string so we also included
<string> and <iostream> header files.
In code, we have initialized tuple info to keep information regarding ‘name’:string, ‘age’:int,
‘salary’:double, ‘year’:int.
tuple<string,int,double,int> info("Pranit",27,25000,86);
Here we have defined and initialized tuple at same place, we
can also use convenience function to initialize value after defining it like,
tuple<string,int,double,int> info; //defining tuple
info = make_tuple("Pranit",27,25000,86); //initializing tuple
To access values of tuple we can use get function,
get<0>(info); // accessing name of info
get<2>(info); // accessing salary of info
get<3>(info); // accessing name of year
If by mistake you give out of range value to get function, it
will give compile time error.
get<5>(info); //error :: index from 0 to 3 is only permissible
get function returns reference to element, so we can change
value of element by assigning value.
get<2>(info) = 20000; // change value of salary from 250000 to 20000
We can extract all values of tuple using std::tie function,
also, if we want to ignore any of the value we can use std::ignore.
tie(name,age,salary,year) = info; // extracted all values in corresponding
variables
tie(name,std::ignore,salary,year) = info; // ignoring age value
Value of one tuple can be assigned to another tuple using
assignment operator.
tuple<string,int,double,int> info1;
info1 = info;
Complete code,
#include <tuple>
#include <iostream>
#include <string>
using namespace std;
int
main(int argc, char* argv[])
{
tuple<string,int,double,int> info("Pranit",27,25000,86);//defining and initilizing
//tuple<string,int,double,int>
info; //defining tuple
//info = make_tuple("Pranit",27,25000,86);
//initilizing tuple
get<0>(info);
// accessing name of info
get<2>(info);
// accessing salary of info
get<3>(info);
// accessing name of year
//get<5>(info); //error
:: index from 0 to 3 is only permissible
get<2>(info)
= 20000; //
change value of salary from 250000 to
20000
string name;
int age;
double salary;
int year;
tie(name,age,salary,year)
= info; //
extracted all values in corresponding variables
tie(name,std::ignore,salary,year)
= info; //
ignoring age value, other values are extracted
tuple<string,int,double,int> info1;
info1 =
info;
return 0;
}
Saturday, April 26, 2014
Calling Conventions
Calling conventions is very important concept of C++
programming. Calling conventions decides two things, how arguments will be
passed on stack and who will clear the stack.
In this article I will describe (and will prove it) two calling
conventions, __cdecl and __stdcall.
In case of both __cdecl and __stdcall, arguments will be
pushed on stack from right to left. Difference is, in __cdecl caller clears the
stack, while in __stdcall callee will clear stack.
Let’s consider following code,
int __stdcall StdCall(int a,int b)
{
return a + b;
}
int __cdecl Cdecl(int a,int b)
{
return a + b;
}
int main(int argc, char* argv[])
{
StdCall(10,20);
Cdecl(10,20);
return 0;
}
In this code, StdCall and Cdecl take two ints and returns
there addition. I kept code simple to illustrate concept.
Now we will see code’s assembly equivalent to understand how
calling conventions do the trick. I am
using Visual Studio to get assembly code. Here I am showing assembly code in
parts.
Call to StdCall
push 20 ;
00000014H
push 10 ;
0000000aH
call ?StdCall@@YGHHH@Z ; StdCall
Definition of StdCall
?StdCall@@YGHHH@Z
PROC ;
StdCall, COMDAT
push ebp
mov ebp,
esp
sub esp,
192 ; 000000c0H
push ebx
push esi
push edi
lea edi,
DWORD PTR [ebp-192]
mov ecx,
48 ;
00000030H
mov eax,
-858993460 ;
ccccccccH
rep stosd
mov eax,
DWORD PTR _a$[ebp]
add eax,
DWORD PTR _b$[ebp]
pop edi
pop esi
pop ebx
mov esp,
ebp
pop ebp
ret 8
?StdCall@@YGHHH@Z
ENDP ;
StdCall
_TEXT ENDS
END
In call to StdCall, it pushes arguments from right to left,
i.e. 20, 10. And look at definition of StdCall, you can see ret 8. This is return statement, and don’t
get confused with return statement of C++, here return statement doesn’t return
value, but pass control from where this function getting called. ret 8 means it will return control by
clearing stack with 8 bytes (adds 8 bytes to stack pointer, esp ). In 32 bit OS
int are of 4 bytes, we are passing two ints so that will make it 8 bytes. So
callee has cleaned the stack.
Now look at Cdecl calling convention.
Call to Cdecl
push 20 ;
00000014H
push 10 ;
0000000aH
call ?Cdecl@@YAHHH@Z ; Cdecl
add esp, 8
Definition of Cdecl
?Cdecl@@YAHHH@Z
PROC ; Cdecl,
COMDAT
push ebp
mov ebp,
esp
sub esp,
192 ; 000000c0H
push ebx
push esi
push edi
lea edi,
DWORD PTR [ebp-192]
mov ecx,
48 ; 00000030H
mov eax,
-858993460 ; ccccccccH
rep stosd
mov eax,
DWORD PTR _a$[ebp]
add eax,
DWORD PTR _b$[ebp]
pop edi
pop esi
pop ebx
mov esp,
ebp
pop ebp
ret 0
?Cdecl@@YAHHH@Z
ENDP ; Cdecl
_TEXT ENDS
Like StdCall, here in Cdecl both the arguments are pushed
from right to left, and then call to function is made. However after call statement,
you can see add esp,
8, which adds 8 to esp. esp points to top of stack. Adding 8 to means it is
clearing 8 bytes (because stack grows from higher to lower memory). So here
caller is clearing stack. Contrary to StdCall here you can see, ret 0, which just returns control and do
not anything to stack pointer. So, in this case caller clears the stack.
Please add comments for your queries and suggestions.
Thursday, April 3, 2014
Never throw exception from destructor
In C++, if you get exception in your code, you can handle it
using try … catch block. If your code in try block throws exception, it will be
caught in catch block.
In catch block
you can either gracefully close, or resume your application depending on
severity of exception.
If you do not handle exception in try.. catch block, C++
runtime will call abort() function and application will crash.
So code which can throw exception should be wrapped in try ..
catch block. So long so good.
Compiler is good at handling one
exception at a time. If your code try to throw more than one exception at a time,
application will definitely crash by calling abort() function. (I don’t know why)
And for the same reason, it is considered to be bad practice,
to throw exception from destructor.
Let’s see some examples to understand concept.
Here, I am throwing exception from try and it will get caught
in catch.
int
main(int argc, char* argv[])
{
try
{
throw "Exc";
}
catch(...)
{
std::cout<<"Exception
caught"<<std::endl;
}
return 0;
}
Output: Exception caught
Now, consider following example, I am throwing exception from
destructor. Destructor will get called
in two cases, 1) You have created object on heap using new operator and, call delete
to destroy object. 2) You have created object on stack, and object goes out of
scope.
class Sample
{
public:
~Sample()
{
throw "Exc";
}
};
int
main(int argc, char* argv[])
{
try
{
Sample s;
throw "ExcMain";
//other
code
}
catch(...)
{
std::cout<<"Exception
caught"<<std::endl;
}
return 0;
}
Output : Crash!!!
When “throw ExcMain”, throws exception, stack unwinding
starts, and your object “s” goes out of scope,
which calls it’s destructor, which will again throw exception.
So you
have two exceptions at a time. And C++ runtime will call abort().
So never throw exception from destructor.
Please give your suggestion and feedback by leaving comment
below article.
Thanks.
Subscribe to:
Posts (Atom)