C++ 11 - Part 1
-
Upload
anil-chopra -
Category
Documents
-
view
224 -
download
4
description
Transcript of C++ 11 - Part 1
C++ 11 – Part 1
Abstract
• C++11 (formerly known as C++0x) is the most recent version
of the standard of the C++ programming language.
• It was approved by ISO on 12 August 2011, replacing C++03.
• C++11 includes several additions to the core language and
extends the C++ standard library
C++ 11 – Part 1
Explicit overrides
• In C++03, it is possible to accidentally create a new virtual function, when one
intended to override a base class function. For example:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int);
};
• Suppose the Derived::some_func is intended to replace the base class version. But
instead, because it has a different signature, it creates a second virtual function.
• This is a common problem, particularly when a user goes to modify the base class.
C++ 11 – Part 1
Explicit overrides
• C++11 provides syntax to solve this problem.
struct Base {
virtual void some_func(float);
};
struct Derived : Base {struct Derived : Base {
virtual void some_func(int) override;
// ill-formed - doesn't override a base class method
};
• The override special identifier means that the compiler will check the base
class(es) to see if there is a virtual function with this exact signature. And if there is
not, the compiler will indicate an error.
C++ 11 – Part 1
final
• Prevent inheriting from classes
• Preventing overriding methods in derived classes
• struct Base1 final { };
• struct Derived1 : Base1 { };
// ill-formed because the class Base1 has been marked final// ill-formed because the class Base1 has been marked final
struct Base2 {
virtual void f() final;
};
struct Derived2 : Base2 {
void f(); // ill-formed because the virtual function Base2::f has been marked final
};
C++ 11 – Part 1
Range-based for statements
• In C++03
for (std::vector<int>::iterator itr = myvector.begin(); itr != myvector.end(); ++itr)
• In C++11, the auto keyword makes this a little better
for (auto itr = myvector.begin(); itr != myvector.end(); ++itr)
• C++11, range-based for statement (or sometimes called “for each”)
for (auto x: myvector) // x is read-only
{
cout << x;
}
C++ 11 – Part 1
Range-based for statements
• If you want to modify the value of x, you can make x a
reference
for (auto& x: myvector) // x is modifiable
{{
cout << ++x;
}
• This syntax works for C-style arrays and anything that supports
an iterator via begin() and end() functions.
• This includes initialization_list
C++ 11 – Part 1
static_assert
• C++03 provides an assert macro that allows testing for
assertions at runtime.
• However, for templated programming, it’s sometimes useful
to be able to test assertions at compile type.
• C++11 provides a new keyword called static_assert that does
a compile-time assertion test.
static_assert(sizeof(int) >= 4, "int needs to be 4 bytes to use this code");
C++ 11 – Part 1
static_assert
• static_assert is checked at compile time, it can not be used to
evaluate assumptions that depend on runtime values.
• static_asserts is primarily useful for checking the size of things
via sizeof() or determining that #defined values are within
certain boundaries.certain boundaries.
• static_assert(__cplusplus > 199711L, "Program requires C++11 capable compiler");
C++ 11 – Part 1
Null pointer constant
void foo(char *);
void foo(int);
foo(NULL); // will call foo(int)
• C++11 provides a null pointer constant: nullptr. It is of type nullptr_t,• C++11 provides a null pointer constant: nullptr. It is of type nullptr_t,
which is implicitly convertible and comparable to any pointer type
• It is not implicitly convertible or comparable to integral types, except
for bool.
• For backwards compatibility reasons, 0 remains a valid null pointer
constant.
C++ 11 – Part 1
Null pointer constant
char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
int i = nullptr; // error
foo(nullptr); // calls foo(nullptr_t), not foo(int);
In standard types headers for C++11, the nullptr_t type should be
declared as:
typedef decltype(nullptr) nullptr_t;
C++ 11 – Part 1
State the output
template<class F, class A>
void Fwd(F f, A a)
{
f(a);
}
void g(int* i) {
std::cout << "Function g called\n";std::cout << "Function g called\n";
}
int main()
{
g(NULL);
g(0);
g(nullptr);
Fwd(g, nullptr);
Fwd(g, NULL);
}
C++ 11 – Part 1
Right angle brackets
vector<vector<int> > vector_of_int_vectors;
• You had to write a space between the two closing angle
brackets.
• You no longer need to worry about it!
vector<vector<int>> vector_of_int_vectors;vector<vector<int>> vector_of_int_vectors;
C++ 11 – Part 1
Type long long int
• In C++03, the largest integer type is long int.
– It is guaranteed to have at least as many usable bits as int.
• This resulted in long int having size of 64 bits on some popular
implementations and 32 bits on others.
• C++11 adds a new integer type long long int to address this
issue.issue.
– It is guaranteed to be at least as large as a long int, and have no fewer
than 64 bits.
• The type was originally introduced by C99 to the standard C,
and most C++ compilers support it as an extension already
C++ 11 – Part 1
Converting Constructor
• A constructor declared without the function-specifier explicit specifies a conversion
from the types of its parameters to the type of its class.
struct foo
{
foo(int x);
foo(char* s, int x = 0); foo(char* s, int x = 0);
foo(float f, int x);
explicit foo(char x);
};
foo bar(foo f)
{
return {1.0f, 5};
}
C++ 11 – Part 1
Koenig lookup
• Koenig Lookup is also commonly known as Argument Dependent Lookup in C++
– You don’t have to qualify the namespace for functions if one or more argument types
are defined in the namespace of the function.
namespace MyNamespace {
class MyClass {};
void doSomething(MyClass);
}
MyNamespace::MyClass obj; // global object
int main() {
doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}
• The compiler correctly identifies the unqualified name doSomething() as the
function declared in namespace MyNamespace by applying the Koenig algorithm.
• The algorithm tells the compiler to not just look at local scope, but also the
namespaces that contain the argument's type.
C++ 11 – Part 1
lvalues and rvaluesint a;
a = 1; // here, a is an lvalue
------------------------------------------------------------
int x;
int& getRef ()
{
return x;
}}
getRef() = 4;
-------------------------------------------------------------
rvalue
int x;
int getVal ()
{
return x;
}
getVal();
C++ 11 – Part 1
rvaluesstring getName ()
{
return "Alex";
}
string name = getName();
getName() is an rvalue.getName() is an rvalue.
But you're assigning from a temporary object, not from some value that has a fixed
location.
Prior to C++11, if you had a temporary object, you could use a "regular" or "lvalue
reference" to bind it, but only if it was const
const string& name = getName(); // ok
string& name = getName(); // NOT ok
C++ 11 – Part 1
rvalues
In C++11, however, there's a new kind of reference, an "rvalue
reference”
string&& name = getName();
See Example1.cpp
Now we have a way to determine if a reference variable refers to
a temporary object or to a permanent object.
The rvalue reference version of the method is helpful if you use a
temporary object
C++ 11 – Part 1
Move constructor
rvalue references are useful to create a move constructor and
move assignment operator
See Example2.cpp
Apply the move constructor here to avoid the expense of a deep
copy by providing the rvalue reference.
Avoid a copy by changing the original, temporary object!
See Solution2.cpp
C++ 11 – Part 1
Move constructor
• If you have a function that returns a const object, it will
cause the copy constructor to run instead of the move
constructor
const ArrayWrapper getArrayWrapper ();
// makes the move constructor useless,
// the temporary is const!
See Example3.cpp
Find the bug and provide a fix
C++ 11 – Part 1
Move constructor
// move constructor
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( other._metadata ) // incorrect
{{
other._p_vals = NULL;
other._size = 0;
}
• std::move
– turns an lvalue into an rvalue
– Use <utility>
C++ 11 – Part 1
std::move
See Solution3.cpp
// move constructor
MetaData (MetaData&& other)
: _name( std::move( other._name ) )
, _size( other._size )
{}{}
// move constructor
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
other._size = 0;
}
C++ 11 – Part 1
Move constructors and implicitly generated
constructors• When you declare any constructor, the compiler will no longer
generate the default constructor for you.
• Adding a move constructor to a class will require you to
declare and define your own default constructor.
• Declaring a move constructor does not prevent the compiler
from providing an implicitly generated copy constructor
• Declaring a move assignment operator does not inhibit the
creation of a standard assignment operator.
C++ 11 – Part 1
Initializer lists
• C++03 has partial support for initializer lists, allowing you to use initializer lists for
simple aggregate data types - structs and C-style arrays
struct Employee
{
int nID;
int nAge;
float fWage;float fWage;
};
Employee sJoe = {1, 42, 60000.0f};
int anArray[5] = { 3, 2, 7, 5, 8 };
• However, this doesn’t work for classes
int anArray[5] = { 3, 2, 7, 5, 8 }; // ok
std::vector<int> vArray[5] = {3, 2, 7, 5, 8}; // not okay in C++03
C++ 11 – Part 1
Initializer lists
• C++11 extends initializer lists so they can be used for all classes.
• This is done via a new template class called std::initializer_list
• If you use an initializer list on a class, C++11 will look for a constructor with a
parameter of type std::initializer_list.
• std::vector<int> vArray[5] = {3, 2, 7, 5, 8};
// calls constructor std::vector<int>(std::initializer_list<int>);
• #include <initializer_list>
• See Example4.cpp
– Apply the initializer list
C++ 11 – Part 1
Initializer lists
• See Solution4.cpp
• std::vector has an initializer_list constructor in C++11
MyArray(const std::initializer_list<T>& x): m_Array(x) MyArray(const std::initializer_list<T>& x): m_Array(x)
// let vector constructor handle population of mArray
{
}
C++ 11 – Part 1
Initializer lists
• initializer_list has iterator functions begin() and end()
• You can also use initializer lists a function parameters, and access the elements in
the same way
int sum(const initializer_list<int> &il)
{
int nSum = 0;
for (auto x: il)
nSum += x;
return nsum;
}
cout << sum( { 3, 4, 6, 9 } );
C++ 11 – Part 1
Uniform initialization
• initializer lists
type variable = { data, elements };
• The uniform initialization syntax takes the following form:
type variable { data, elements }; // note: no assignment operator
• This style of initialization will work for both plain aggregate data types
(structs and C-style arrays) and classes.
• For classes, the following rules are observed:
– If there is an initialization_list constructor of the appropriate type, that
constructor is used
– Otherwise the class elements are initialized using the appropriate constructor
C++ 11 – Part 1
Uniform initialization
class MyStruct
{
private:
int m_nX;
float m_nY;float m_nY;
public:
MyStruct(int x, float y): m_nX(x), m_nY(y) {};
};
MyStruct foo {2, 3.5f};
C++ 11 – Part 1
Uniform initialization
• initializer_list constructor takes precedence over other
constructors when doing uniform initialization.
std::vector<int> v1(8);
// creates an empty vector of size 8, using the int
constructorconstructor
std::vector<int> v1{8};
// creates a one-element vector with data value 8,
// using the initializer_list constructor
C++ 11 – Part 1
Uniform initialization
• You can also use the uniform initialization syntax when calling or return
values in functions
void useMyStruct(MyStruct x)
{
}
useMyStruct({2, 3.5f});
// use uniform initialization to create a MyStruct implicitly
MyStruct makeMyStruct(void)
{
return {2, 3.5f};
// use uniform initialization to create a MyStruct implicitly
}
C++ 11 – Part 1
Type inference
• In C++11, if the compiler can infer the type of a variable at the
point of declaration, instead of putting in the variable type,
you can just write auto
int x = 4;
can now be replaced with
auto x = 4;
vector<int> vec;
auto itr = vec.iterator();
// instead of vector<int>::iterator itr
C++ 11 – Part 1
Type inference
• See Example5.cpp
– Apply type inference to simplify the code in both the template function and
the code in main()
template <typename BuiltType, typename Builder>
void makeAndProcessObject (const Builder& builder)
{{
BuiltType val = builder.makeObject();
// do stuff with val
}
int main()
{
MyObjBuilder builder;
makeAndProcessObject<MyObj>( builder );
return 0;
}
C++ 11 – Part 1
Type inference
• See Solution5.cpp
– Now you only need a single template parameter, and that parameter is easily
inferred when calling the function:
template <typename Builder>
void makeAndProcessObject (const Builder& builder)
{{
auto val = builder.makeObject();
// do stuff with val
}
int main()
{
MyObjBuilder builder;
makeAndProcessObject( builder );
return 0;
}
C++ 11 – Part 1
New Return Value Syntax
int multiply (int x, int y);
• In C++11, you can now put the return value at the end of the
function declaration, substituting auto for the name of the
return type, if you want to
auto multiply (int x, int y) -> int;
• See Example6.cpp
– Identify the error
– Provide a fix
C++ 11 – Part 1
decltype
• decltype lets you extract the type from a variable (or any
other expression)
int x = 3;
decltype(x) y = x; // same thing as auto y = x;
• See Example7.cpp
– Provide a clean solution
C++ 11 – Part 1
Variadic function
Consider the following code – to handle any number of arguments
#include <initializer_list>
int sum(std::initializer_list<int> numbers)
{
int total = 0;
for(auto i = numbers.begin(); i != numbers.end(); i++)for(auto i = numbers.begin(); i != numbers.end(); i++)
{
total += *i;
}
return total;
}
// later in code
sum( { 1, 2, 3, 4, 5 } ); // returns 15
C++ 11 – Part 1
Variadic templates
• Variadic templates can take variadic arguments.
int sum() // gets called when no arguments are passed
{
return 0;
}
template<typename ... Types>
int sum (int first, Types ... rest)
{
return first + sum(rest...);
}
// later in code
sum(1, 2, 3, 4, 5); //returns 15
C++ 11 – Part 1
Lambda functions and expressions
• One of the most exciting features of C++11 is ability to create lambda
functions (sometimes referred to as closures).
• A lambda function is a function that you can write inline in your source
code (usually to pass in to another function, similar to the idea of
a functor or function pointer).
• With lambda, creating quick functions has become much easier
– No need to write separate functions
int main()
{
auto func = [] () { cout << "Hello world"; };
func(); // now call the function
}
C++ 11 – Part 1
Another example
class AddressBook
{
public:
template<typename Func>
std::vector<std::string> findMatchingAddresses (Func func) {
std::vector<std::string> results;
for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr )
{
if ( func( *itr ) )
{
results.push_back( *itr );
}
}
return results;
}
private:
std::vector<std::string> _addresses;
};
C++ 11 – Part 1
Another example
AddressBook global_address_book;
vector<string> findAddressesFromOrgs ()
{
return global_address_book.findMatchingAddresses(
// we're declaring a lambda here; the [] signals the start// we're declaring a lambda here; the [] signals the start
[] (const string& addr) { return addr.find( ".org" ) != string::npos; }
);
}
C++ 11 – Part 1
Variable Capture with lambdas
string name;
cin>> name;
return global_address_book.findMatchingAddresses(
// notice that the lambda function uses the the variable 'name'
[&] (const string& addr) { return addr.find( name ) != string::npos; } [&] (const string& addr) { return addr.find( name ) != string::npos; }
);
int min_len = 0;
cin >> min_len;
return global_address_book.find( [&] (const string& addr) {
return addr.length() >= min_len; } );
C++ 11 – Part 1
lambda options
• [] Capture nothing (or, a scorched earth strategy?)
• [&] Capture any referenced variable by reference
• [=] Capture any referenced variable by making a copy
• [=, &foo] Capture any referenced variable by making a copy, but capture
variable foo by reference
• [bar] Capture bar by making a copy; don't copy anything else
• [this] Capture the this pointer of the enclosing class• [this] Capture the this pointer of the enclosing class
C++ 11 – Part 1
Lambda and STL
vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for ( auto itr = v.begin(), end = v.end(); itr != end; itr++ )
{
cout << *itr;cout << *itr;
}
vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for_each( v.begin(), v.end(), [] (int val) { cout << val; } );
C++ 11 – Part 1
std::function
• The new std::function is a great way of passing around lambda functions both as
parameters and as return values. It allows you to specify the exact types for the
argument list and the return value in the template.
class AddressBook {
public:
std::vector<string> findMatchingAddresses (std::function<bool (const string&)> func) {
std::vector<string> results;
for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr ) {
// call the function passed into findMatchingAddresses and see if it matches
if ( func( *itr ) ) {
results.push_back( *itr );
}
}
return results;
}
private:
std::vector<string> _addresses;
};
C++ 11 – Part 1
Example – Handling exceptions
vector<int> elements(3);
vector<int> indices(3);
indices[0] = 0;
indices[1] = -1; // This is not a subscript. It will trigger the exception.
indices[2] = 2;
// Use the values from the vector of index values to fill the elements vector.
// Use a try/catch block to handle invalid access to the elements vector.
try
{
for_each(indices.begin(), indices.end(),
[&] (int index) { elements.at(index) = index; });
}
catch (const out_of_range& e)
{
cerr << "Caught '" << e.what() << "'." << endl;
};
C++ 11 – Part 1
Making delegates with lambda
• When you call a normal function, all you need is the function
itself.
• When you call a method on an object, you need two things:
the function and the object itself.
• See Example8.cpp
– Provide a clean solution by using a delegate with lambda