Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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
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
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
C++ 11 Part 1
C++ 11 Part 1
C++ 11 Part 1
static_assert
C++03 provides an assert macro that allows testing for
assertions at runtime.
However, for templated programming, its 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.
C++ 11 Part 1
C++ 11 Part 1
// error
foo(nullptr);
type should be
C++ 11 Part 1
C++ 11 Part 1
C++ 11 Part 1
C++ 11 Part 1
Converting Constructor
C++ 11 Part 1
Koenig lookup
C++ 11 Part 1
C++ 11 Part 1
rvalues
string getName ()
{
return "Alex";
}
string name = getName();
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
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;
};
Employee sJoe = {1, 42, 60000.0f};
int anArray[5] = { 3, 2, 7, 5, 8 };
C++ 11 Part 1
Initializer lists
C++11 extends initializer lists so they can be used for all classes.
If you use an initializer list on a class, C++11 will look for a constructor with a
parameter of type std::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)
// let vector constructor handle population of mArray
{
}
C++ 11 Part 1
Initializer lists
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;
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
constructor
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
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++)
{
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()
{
return 0;
}
C++ 11 Part 1
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
[] (const string& addr) { return addr.find( ".org" ) != string::npos; }
);
}
C++ 11 Part 1
C++ 11 Part 1
lambda options
[]
[&]
[=]
[=, &foo]
[bar]
[this]
C++ 11 Part 1
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
C++ 11 Part 1
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.