c++11 New Features

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

C++ 11 new features

Type Inference in c++ (auto and decltype)

Type Inference referes to automatic deduction of the data type of an expression in a programming language. Before C++ 11,
each data type needed to be explicitly declared at compile-time, limiting the values of an expression at runtime but after the
new version of C++, many keywords are included which allows a programmer to leave the type deduction to the compiler
itself.

1. auto  the auto keyword specifies that the type of the variable that is being declared will be automatically deducted
from its initializer. In case of function, if their return type is auto then that will be evaluated by return type expression
at runtime. Good use of auto is to avoid long initializations when creating iterators for containers.

Note: the variable declared with auto keyword should be initialized at the time of its declaration only or else there will
be a compiler-time error.

Example –

#include <iostream>
using namespace std;

auto showMessage(string str){


return "Hello ! " +str;
}

int main(){
auto num = 4;
auto f = 3.45f;
auto ch = 'a';
auto d = 3.54;
auto ptr = &num;

auto greet = showMessage("subodh");


cout << greet << endl;
cout << "num --> " << typeid(num).name() << endl;
cout << "f --> " << typeid(f).name() << endl;
cout << "ch --> " << typeid(ch).name() << endl;
cout << "d --> " << typeid(d).name() << endl;
cout << "ptr --> " << typeid(ptr).name() << endl;
cout << "greet --> " << typeid(greet).name() << endl;

return 0;
}
Here, we have used typeid for getting the type of variable.

Typeid is an operator which is used where the dynamic type of an object needs to be known. typeid(num).name()
returns the data type of num, for example, it returns ‘I’ for integer, ‘d’ for doubles, ‘f’ for float, ‘pi’ for pointer of integer type,
etc. But the actual name returned is mostly compiler dependent.

Example –

#include <iostream>
#include <set>
using namespace std;

int main(){
set<string> st;
st.insert({"jennifier", "selena", "Elly", "salma", "tailor"});
for(auto it = st.begin(); it != st.end(); ++it){
cout << *it << endl;
}

return 0;
}
In this example, st.begin() returns the reference of first element from set. Hence, auto keyword deduction the expression and
it variable become of that type (reference type).

2. decltype keyword  It inspects the declared type of an entity or the type of an expression. ‘auto’ lets you declared a
variable with a particular type whereas decltype lets you extract the type from the variable so decltype is sort of an
operator that evaluates the type of passes expression. Let’s understand with the help of example –

#include <iostream>
using namespace std;

int func1() { return 10; }


char func2() { return 'g'; }

int main(){
decltype(func1()) x;
decltype(func2()) y;

cout << "type of x : " << typeid(x).name() << endl;


cout << "type of y : " << typeid(y).name() << endl;

return 0;
}
Here, on the basis of func1() and func2() return type, the data type of variable x and y is considered by decltype keyword.
Example – 2
#include <iostream>
using namespace std;
int main(){
int x = 5;
decltype(x) j = x +5;
cout << endl << "type of j : " << typeid(j).name() << endl;
return 0;
}
In this example, type of j is decided by decltype operator after the calculating expression and its return value.

decltype vs typeid
 decltype gives the type information at compile time while typeid gives at runtime.
 If we have a base class reference (or pointer) referring to (or pointing to) a derived class object, the decltype would
give type as base class reference or pointer but, typeid would give the derived type reference or pointer.

noexcept 
Every programming language, we need to have a mechanism to handle the exception, so in C++ we use noexcept to handle
exception. This keyword in introduced since C++ 11.

by declaring a function, a method, or a lambda-function as noexcept, you specify that these does not throw an exception and
if they throw, you do not care and let the program just crash.
void func1() noexcept; // does not throw
void func2() noexcept(true); // does not throw
void func3() throw(); // does not throw
void func4() noexcept(false); // may throw
throw() is equivalent to noexcept(true) but was deprecated with C++11 and will be removed with C++20. The noexcept
specification is part of the function type but cannot used for function overloading. There are two good reason for the use of
noexcept – first, if a function is specified as noexcept, it can be safely used in a non-throwing function . second, it is an
optimisation opportunity for the compiler.
Each function in C++ is either non-throwing or potentially throwing. Potentially throwing means:
1. The function may use a function that may throw error.
2. The function is declared without a noexcept specification
3. The function uses a dynamic_cast to a reference type.
There are six member functions which are implicitly non-throwing.
 Default constructor and destructor
 Move and copy constructor
 Move and copy assignment operator

What happen when you throw an exception in a function which is declared as non-throwing? In this case, std::terminate is
called. Std::terminate calls the currently installed std::terminate_handler which calls std::abort by default. The result is an
abnormal program termination.
Let’s understand with the help of example –
Example – 1 (In this example we are creating multiple functions which are using noexcept keyword to deal with exception. We
have also created one function which is not declared with noexcept and throws the exception.

---
--
Lambda expression in C++
C++ 11 introduced lambda expression to allow a function which can be used for short snippets of code that are not going to be
reused and therefore do not require a name.
In another word we can say that C++ lambda expression allows us to defined anonymous function which can be either used
inline of passes as argument.
Let’s understand with the help of example –
Example – 1 (In this example we create a lambda expression function to print “hello world”)
#include <iostream>
using namespace std;

int main(){
// lambda function to print "Hello World"
auto greet = [](){
cout << "Hello World";
};
greet(); // call lambda function
return 0;
}
In this example –
greet is a variable that store the lambda function. It is auto type means its type is automatically deduced by compiler.
Like an ordinary function, lambda function is also called as shown in this example.

Lambda function with parameter


Just like a regular function, lambda expression can also take parameter. For example –
Example – 2 (In this example lambda function take parameter)
#include <iostream>
using namespace std;

int main(){
auto add = [](size_t a, size_t b){
cout << "sum : " << a + b;
};
add(12, 13);
return 0;
}
In this example, we passes two argument to lambda function.
Following is the general form of lambda function –
[capture_clause] (parameter_list){
// definition of method
}

[]  with the help of this lambda function capture the external variables. There are three way to capture the external
variables by lambda expression –
 Capture by reference
 Capture by value
 Capture by both (mixed capture)
Following syntax are used for capturing variables:
[&]  capture the all external variable by reference
[=]  capture all external variables by value
[a, &b]  capture a by value and b by reference
Let’s understand with the help of example –
#include <iostream>
using namespace std;

int main(){
size_t add;
auto sum = [] (size_t a, size_t b){
add = a + b;
cout << "sum : " << add << endl;
};
return 0;
}
When we executes this program then we will get compile time error. Because, sum is not access by lambda function. Variable
is out of scope for lambda function. To access that variable we need capture block. Following is another example that shows
the solution of above problem
#include <iostream>
using namespace std;

int main(){
size_t add = 0;
auto sum = [&] (size_t a, size_t b){
add = (a + b);
cout << "sum : " << add << endl;
};
return 0;
}
In this example – lambda function capture the external variable by reference. Here, ‘&’ operator indicates that lambda
function can access the all external variable by reference.

#include <iostream>
using namespace std;

int main(){
size_t initial_value = 0;
cout << "Value before modification : " << initial_value << endl;
auto modified_value = [&initial_value] (size_t value){
initial_value = value;
};
modified_value(900);
cout << "After modificaton : " << initial_value << endl;
return 0;
}
In this example, variable initial_valueis access by reference by lambda function.
Example – (this example shows call by value by lambda function)
#include <iostream>
using namespace std;

int main(){
size_t initial_value = 100;

auto add_to_sum = [initial_value] (size_t value){


return initial_value + value;
};

size_t final_value = add_to_sum(21);


cout << "final value : " << final_value << endl;
return 0;
}

Example – (this program shows call by reference and call by value as well)
#include <iostream>
#include <vector>
using namespace std;

int main(){
vector<int> v1 = {3, 1, 7, 9};
vector<int> v2 = {10, 2, 7, 16, 9};

// call by reference
auto pushinto = [&] (size_t num) {
v1.push_back(num);
v2.push_back(num);
};

pushinto(102);

// v1 access through call by value


auto get_value = [v1] () {
for(auto itr = v1.begin(); itr != v1.end(); ++itr) {
cout << *itr << " ";
}
};
get_value();
cout << endl;

return 0;
}
In this example – pushinto() is a lambda function that access the all externals variable through call by reference. And
get_value() is another lambda function the get the value from external variable through call by value.

Lambda function with return type


Like normal functions, C++ lambda function also return some value. Following example demonstrate it.
#include <iostream>
using namespace std;

int main(){
auto add = [] (size_t a, size_t b){
return (a + b);
};
cout << "Sum : " << add(12, 13) << endl;
return 0;
}
In this example, add variable stores the value return by lambda function.

The compiler can implicitly deduce the return type of the lambda function based on the return statement. For example – in
above example we have no explicitly defined return type for the lambda function. However, in some complex cases e.g.
conditional statements, the compiler can’t determine the return type and explicit specification is required. For example –
#include <iostream>
using namespace std;

int main() {
auto operation = [] (size_t a, size_t b, string op) -> double {
if(op == "sum"){
return a + b;
}
else{
return (a + b) /2.0;
}
};
cout << operation(12, 15, "div") << endl;
return 0;
}
In this example, we have explicitly defined the return type for lambda expression. Because, here in different condition return
type is different.

We can use lambda expression inside another function as arguments –


Following program shows how we use lambda expression as the arguments for another function.
Example –
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main(){
vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};
int even_count = count_if(nums.begin(), nums.end(), [] (int num) {
return num % 2 == 0;
});
cout << "There are " << even_count << "even numbers." << endl;
return 0;
}
In this example – count_if() is a function that is used to count number according to some condition. In this example, count_if()
method is used for counting the total number of even number available in vector. For the condition in count_if() method we
defined a lambda expression as argument to count_if() method. In this example –
[] (int num) {
return num % 2 == 0;
}
is lambda expression which is passes as the argument for count_if().

Example – (following example show the lambda function is used as the argument in iteration)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void printVector(vector<int> v){


// lambda function to print vector's element
for_each(v.begin(), v.end(), [] (int i){
cout << i << " ";
});
}

int main(){
vector<int> v {4, 1, 3, 5, 2, 3, 1, 7};
printVector(v);
return 0;
}

Example – (following example display that element which are greater than 4)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
vector<int> v {4, 1, 3, 5, 2, 3, 1, 7};
for_each(v.begin(), v.end(), [] (int i){
if( i >= 4)
cout << i << " ";
});
return 0;
}

nullptr 
It is keyword which is introduced in C++ 11. It allow programmers to use nullptr in place of NULL or 0 for specifying a pointer
which refers to no value. Let’s understand with the help of example –
#include <iostream>
using namespace std;

void fun(int N) { cout << "fun(int)"; return;}


void fun(char *s) { cout << "fun (char)"; return;}
int main(){
fun(NULL);
return 0;
}
When we compile this program then we will get error message.

What is the problem with above program?


NULL is typically defined as (void *) 0 and conversion of NULL to integral types is allowed. So the function call fun (NULL)
becomes ambiguous.

How does nullptr solve the problem?


In the above program, if we replace NULL with nullptr, we get the output as “fun(char)”.

nullptr is a keyword that can be used at all places where NULL is expected. Like NULL, nullptr is implicitly convertible and
comparable to any pointer type. Unlike NULL, it is not implicitly convertible or comparable to integral types. Example –
#include <iostream>
int main(){
int x = NULL;
return 0;
}
Here, NULL is acceptable for int type because, NULL is implicitly comparable and convertible into int type. But in place of NULL,
we use nullptr then we will get error. Example –
#include <iostream>
int main(){
int x = nullptr;
return 0;
}
Because, nullptr is not convertible and comparable to any type. It is convertible and compare to any pointer type only.
Therefore, in the above example when we replace ‘NULL’ with ‘nullptr’ then we will get error message.

As a side note, nullptr is convertible to bool.

#include <iostream>
using namespace std;

int main(){
int *ptr = nullptr;
if(ptr){
cout << "true";
}
else{
cout << "false";
}
return 0;
}

Override identifier
There may be situation when a programmer makes a mistake while override a function. So, to keep track of such an error, C++
11 has come up with the override identifier. It will make the compiler check the base class to see if there is a virtual function
with this exact signature. And if there is not, the compiler will show an error.

If the override identifier is used with a member function, then compiler makes sure that the member function exists in the
base class, and also the compiler restricts the program to compile otherwise. Let’s understand with the help of example –
#include <iostream>
using namespace std;

class Base{
public:
virtual void func(){
cout << "I am in base" << endl;
}
};

class derived : public Base{


public:
void func(int a){
cout << "I am in derived class " << endl;
}
};

int main(){
Base b;
derived d;
cout << "compiler successfully" << endl;
return 0;
}
In this example – programmer try to override func() method. But did a silly mistake and redefined with a different signature
which was not detected by compiler. However, the program is not actually what the user wanted. So, the get rid of such silly
mistakes to be on the safe side, the override identifier can be used.
Let’s understand with the help of example –
#include <iostream>
using namespace std;

class Base{
public:
void func(){
cout << "I am from Base class " << endl;
}
};

class Derived : public Base{


public:
void func(int a) override{
cout << "I am from Derived class " << endl;
}
};

int main(){
Base base;
Derived derived;
cout << "successfully compiled !" << endl;
return 0;
}
In this example – we can see the programmer override func() function with override keyword. When we compiler this program
then we will get compile time error because, by mistake programmer change the signature of func() function in derived class.
But, due to override keyword compiler take care about it and show error message.

In short, it serves the following functions. It helps to check if:


 There is a method with the same name in the parent class.
 The method in the parent class is declared as “virtual” which means it was intended to be rewritten.
 The method in the parent class has the same signatures as the method in the subclass.

Unordered containers
In C++ 11, there are 4 types’ unordered containers – unordered_map, unordered_set, unordered_multimap,
unordered_multiset.

Move semantic 
The content of the objects can be moved between the objects instead of copying the contents from one object to another
object by making use of Move Semantics in C++ and the move is possible
https://www.educba.com/c-plus-plus-move-semantics/  study from this link.

You might also like