C++ 11 - Part 1

49
C++ 11 – Part 1 C++ 11 Part 1

description

C++ 11

Transcript of C++ 11 - Part 1

C++ 11 – Part 1

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

C++ 11 – Part 1

Question Time

Please try to limit the questions to the topics discussed during the session.Participants can clarify other doubts during the breaks.Thank you.