SlideShare a Scribd company logo
Beginning Direct3D Game Programming:
C++11 Primer
jintaeks@gmail.com
Division of Digital Contents, DongSeo University.
March 2016
C++11
 C++11 is a version of the standard for the programming
language C++.
 It was approved by International Organization for
Standardization (ISO) on 12 August 2011,
replacing C++03,[1] and superseded by C++14 on 18 August
2014.[2]
 Although one of the design goals was to prefer changes to
the libraries over changes to the core language,[4] C++11 does
make several additions to the core language.
2
Design goals
 Maintain stability and compatibility with C++98 and possibly
with C.
 Prefer introducing new features via the standard library, rather
than extending the core language.
 Improve C++ to facilitate systems and library design, rather
than introduce new features useful only to specific
applications.
3
Extensions to the C++ core language
 Rvalue references and move constructors.
 Extern template
 Initializer lists
 Uniform initializations
 Type inference
 Ranged-based for loop
 Lambda functions and expressions
 Alternative function syntax
 Explicit override and final
 Null pointer constant
 Explicit conversion operator
 …
4
Rvalue references and move constructors
 rvalues? as they often lie on the right side of an assignment.
 In C++03 and before, temporaries were intended to never be
modifiable and were considered to be indistinguishable from
const T& types.
 C++11 adds a new non-const reference type called an rvalue
reference, identified by T&&.
 This refers to temporaries that are permitted to be modified
after they are initialized, for the purpose of allowing "move
semantics".
5
 If a std::vector<T> temporary is created or returned from a
function, it can be stored only by creating a new
std::vector<T> and copying all the rvalue's data into it.
 If std::vector<T> is a C++03 version without a move
constructor, then the copy constructor will be invoked with
a const std::vector<T>&, incurring a significant memory
allocation.
 Move constructor not only forgoes the expense of a deep
copy, but is safe and invisible.
6
std::move(), perfect forwarding
 For safety reasons, a named variable will never be considered
to be an rvalue even if it is declared as such. To get an rvalue,
the function template std::move() should be used.
 Due to the nature of the wording of rvalue references, and to
some modification to the wording for lvalue references
(regular references), rvalue references allow developers to
provide perfect function forwarding.
7
basic concepts of rvalue
class KTest {
public:
KTest() {
std::cout << "constructorrn";
}
KTest( const KTest& rhs ) {
std::cout << "copy constructorrn";
}
~KTest() {
std::cout << "destructorrn";
}
};
8
KTest F( KTest t ) {
return t;
}
void G( const KTest& t ) {
std::cout << "lvalue ref G " << std::endl;
}
void G( KTest&& t ) {
//KTest u = std::move( t );
//KTest u = t;
std::cout << "rvalue ref G " << std::endl;
}
int main() {
KTest t;
KTest u = t;
u = F( KTest() );
std::cout << "rnbefore call Grn";
G( KTest() );
}
9
constructor
copy constructor
constructor
copy constructor
destructor
destructor
before call G
constructor
lvalue ref G
destructor
destructor
destructor
KTest F( KTest t ) {
return t;
}
void G( const KTest& t ) {
std::cout << "lvalue ref G " << std::endl;
}
void G( KTest&& t ) {
//KTest u = std::move( t );
//KTest u = t;
std::cout << "rvalue ref G " << std::endl;
}
int main() {
KTest t;
KTest u = t;
u = F( KTest() );
std::cout << "rnbefore call Grn";
G( KTest() );
}
10
constructor
copy constructor
constructor
copy constructor
destructor
destructor
before call G
constructor
rvalue ref G
destructor
destructor
destructor
KTest F( KTest t ) {
return t;
}
void G( const KTest& t ) {
std::cout << "lvalue ref G " << std::endl;
}
void G( KTest&& t ) {
KTest u = std::move( t );
//KTest u = t;
std::cout << "rvalue ref G " << std::endl;
}
int main() {
KTest t;
KTest u = t;
u = F( KTest() );
std::cout << "rnbefore call Grn";
G( KTest() );
}
11
We want to call the move
constructor of 'u'.
A named variable will never be
considered to be an rvalue even if it
is declared as such. To get an rvalue,
the function
template std::move() should be used.
move constructor
struct A {
std::string s;
A() : s( "test" ) { std::cout << "constructor An"; }
A( const A& o ) : s( o.s ) { std::cout << "copy constructor An"; }
A( A&& o ) : s( std::move( o.s ) ) { std::cout << "move constructor An"; }
};
A f( A a ) {
return a;
}
struct B : public A {
std::string s2;
int n;
};
B g( B b ) {
return b;
}
12
we expect below things in 'B':
* implicit move constructor B::(B&&)
* calls A's move constructor
* calls s2's move constructor
* and makes a bitwise copy of n
* but in Visual Studio 2013, implicit
functions do not call base class's
corresponding functions.
int main() {
std::cout << "Trying to move An";
A a1 = f( A() ); // move-construct from rvalue temporary
std::cout << "Before move, a1.s = " << a1.s << "n";
A a2 = std::move( a1 ); // move-construct from xvalue
std::cout << "After move, a1.s = " << a1.s << "n";
std::cout << "Trying to move Bn";
B b1 = g( B() );
std::cout << "Before move, b1.s = " << b1.s << "n";
B b2 = std::move( b1 ); // calls implicit move ctor
std::cout << "After move, b1.s = " << b1.s << "n";
}
13
Trying to move A
constructor A
move constructor A
Before move, a1.s = test
move constructor A
After move, a1.s =
Trying to move B
constructor A
copy constructor A
Before move, b1.s = test
copy constructor A
After move, b1.s = test
struct A {
std::string s;
A() : s( "test" ) { std::cout << "constructor An"; }
A( const A& o ) : s( o.s ) { std::cout << "copy constructor An"; }
A( A&& o ) : s( std::move( o.s ) ) { std::cout << "move constructor An"; }
};
struct C : public A {
std::string s2;
int n;
C() : A() { std::cout << "constructor Cn"; }
C( const C& o ) : A( o ) { std::cout << "copy constructor Cn"; }
C( C&& o ) : A( std::move( o ) ) { std::cout << "move constructor Cn"; }
//C( C&& o ) : A( o ) { std::cout << "move constructor Cn"; }
};
14
KTest u = t; differs from u = t;
class KTest {
public:
KTest() {
std::cout << "constructorrn";
}
KTest( const KTest& rhs ) {
std::cout << "copy constructorrn";
}
~KTest() {
std::cout << "destructorrn";
}
KTest& operator=( const KTest& rhs ) {
std::cout << "operator=rn";
return *this;
}
};
int main() {
KTest t;
KTest u = t;
KTest v;
v = t; // this is same as v.operator=(t);
}15
constructor
copy constructor
constructor
operator=
destructor
destructor
destructor
real world example
class MemoryBlock {
public:
explicit MemoryBlock( size_t length )
: _length( length )
, _data( new int[ length ] ) {
std::cout << "In MemoryBlock(size_t). length = " << _length << "." << std::endl;
}
// Destructor.
~MemoryBlock() {
std::cout << "In ~MemoryBlock(). length = " << _length << ".";
if( _data != nullptr ) {
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
_data = nullptr;
}
std::cout << std::endl;
}
16
MemoryBlock( const MemoryBlock& other )
: _length( other._length )
, _data( new int[ other._length ] ) {
std::cout << "In MemoryBlock(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
std::copy( other._data, other._data + _length, _data );
}
MemoryBlock& operator=( const MemoryBlock& other ) {
std::cout << "In operator=(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
if( this != &other ) {
delete[] _data;
_length = other._length;
_data = new int[ _length ];
std::copy( other._data, other._data + _length, _data );
}
return *this;
}17
// Move constructor.
MemoryBlock( MemoryBlock&& other )
: _data( nullptr )
, _length( 0 ) {
std::cout << "In MemoryBlock(MemoryBlock&&). length = "
<< other._length << ". Moving resource." << std::endl;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
18
// Move assignment operator.
MemoryBlock& operator=( MemoryBlock&& other ) {
std::cout << "In operator=(MemoryBlock&&). length = "
<< other._length << "." << std::endl;
if( this != &other ) {
// Free the existing resource.
delete[] _data;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
return *this;
}
19
Modification to the definition of plain old data
 In C++03, a class or struct must follow a number of rules for
it to be considered a plain old data(POD) type.
 Types that fit this definition produce object layouts that are
compatible with C, and they could also be initialized statically.
 if someone were to create a C++03 POD type and add a non-
virtual member function, this type would no longer be a POD
type.
 C++11 relaxed several of the POD rules, by dividing the POD
concept into two separate concepts:trivial and standard-
layout.
20
A class with complex move and copy constructors
may not be trivial, but it could be standard-
layout and thus interop with C.
trivial
 it is legal to copy data around via memcpy, rather than having
to use a copy constructor.
① Has a trivial default constructor. This may use the default
constructor syntax(SomeConstructor() = default;).
② Has trivial copy and move constructors, which may use the
default syntax.
③ Has trivial copy and move assignment operators, which may
use the default syntax.
④ Has a trivial destructor, which must not be virtual.
21
standard-layout
 It orders and packs its members in a way that is compatible
with C.
① It has no virtual functions
② It has no virtual base classes
③ All its non-static data members have the same access control
(public, private, protected)
④ All its non-static data members, including any in its base
classes, are in the same one class in the hierarchy
⑤ The above rules also apply to all the base classes and to all
non-static data members in the class hierarchy
⑥ It has no base classes of the same type as the first defined
non-static data member
22
#include <type_traits>
struct X {
// It means that you want to use the compiler-generated version
// of that function, so you don't need to specify a body.
X() = default;
};
struct Y {
Y() {};
};
int main() {
static_assert( std::is_trivial<X>::value, "X should be trivial" );
static_assert( std::is_pod<X>::value, "X should be POD" );
static_assert( !std::is_trivial<Y>::value, "Y should not be trivial" );
static_assert( !std::is_pod<Y>::value, "Y should not be POD" );
}
23
Extern template
 In C++03, the compiler must instantiate a template whenever
a fully specified template is encountered in a translation unit.
 If the template is instantiated with the same types in many
translation units, this can dramatically increase compile
times.
 C++11 now provides this syntax:
extern template class std::vector<MyClass>;
24
Initializer lists
 C++03 inherited the initializer-list feature from C. A struct or
array is given a list of arguments in braces, in the order of the
members' definitions in the struct.
struct Object {
float first;
int second;
};
Object scalar = {0.43f, 10}; //One Object, with first=0.43f and second=10
Object anArray[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; //An array of three
Objects
25
 C++03 allows initializer-lists only on structs and classes that
conform to the Plain Old Data (POD) definition.
 C++11 extends initializer-lists, so they can be used for all
classes including standard containers like std::vector.
class SequenceClass {
public:
SequenceClass(std::initializer_list<int> list);
};
SequenceClass some_var = {1, 4, 5, 6};
 This constructor is a special kind of constructor, called an
initializer-list-constructor. Classes with such a constructor are
treated specially during uniform initialization.
26
first-class citizen
 In programming language design, a first-class
citizen (also type, object, entity, or value) in a given
programming language is an entity which supports all the
operations generally available to other entities.
 The simplest scalar data types, such as integer and floating-
point numbers, are nearly always first-class.
 In C++, arrays is not first-class: they cannot be assigned as
objects or passed as parameters to a subroutine.
 For example, C++ doesn't supports array assignment, and
when they are passed as parameters, only the position of their
first element is actually passed—their size is lost.
27
 The class std::initializer_list<> is a first-class C++11 standard
library type.
 However, they can be initially constructed statically by the
C++11 compiler only via use of the {} syntax.
void function_name(std::initializer_list<float> list);
function_name({1.0f, -3.45f, -0.4f});
 Standard containers can also be initialized in these ways:
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" });
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" };
28
My own initializer_list?
29
The initializer_list is a real
type, it can be used in other
places besides class
constructors. Regular
functions can take typed
initializer lists as arguments.
But! std::initializer_list is
treated specially. So you can
not create your own
initializer_list.
Uniform initialization
 C++03 has a number of problems with initializing types.
Several ways to do this exist, and some produce different
results when interchanged.
 For example, The traditional constructor syntax can look like a
function declaration.
 Only aggregates and POD types can be initialized with
aggregate initializers (using SomeType var = {/*stuff*/};).
30
 C++11 provides a syntax that allows for fully uniform type
initialization that works on any object.
struct BasicStruct {
int x;
double y;
};
struct AltStruct {
AltStruct(int x, double y) : x_{x}, y_{y} {}
private:
int x_;
double y_;
};
BasicStruct var1{5, 3.2};
AltStruct var2{2, 4.3};
31
struct IdString {
std::string name;
int identifier;
};
IdString get_string() {
return {"foo", 42}; //Note the lack of explicit
type.
}
 The following code will call the initializer list constructor, not
the constructor of std::vector that takes a single size
parameter and creates the vector with that size.
std::vector<int> the_vec{4};
32
Type inference: decltype
 In C++03 (and C), to use a variable, its type must be specified
explicitly.
 However, with the advent of template types and template
metaprogramming techniques, the type of something,
particularly the well-defined return value of a function, may
not be easily expressed.
33
well-defined
 In mathematics, an expression is called well-defined if its
definition assigns it a unique interpretation or value.
Otherwise, the expression is said to be not well-defined .
 A function is well-defined if it gives the same result when the
representation of the input is changed without changing the
value of the input.
 For instance if f takes real numbers as input, and if f(0.5) does
not equal f(1/2) then f is not well-defined.
34
 C++11 allows this to be mitigated in two ways. First, the
definition of a variable with an explicit initialization can use
the auto keyword.
auto some_strange_callable_type = std::bind(&some_function, _2,
_1, some_object);
auto other_variable = 5;
for (std::vector<int>::const_iterator itr = myvec.cbegin(); itr !=
myvec.cend(); ++itr)
for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
 Further, the keyword decltype can be used to determine the
type of expression at compile-time.
int some_int;
decltype(some_int) other_integer_variable = 5;
35
when to use
// will not compiled!
template<typename T, typename U>
decltype(T+U) add( T t, U u )
{
return t + u;
}
template<typename T, typename U>
auto add2( T t, U u ) -> decltype( t + u ) // return type depends on template parameters
{
return t + u;
}
36
template<typename T, typename U>
auto add2( T t, U u ) -> decltype( t + u ) // return
type depends on template parameters
{
return t + u;
}
int main() {
printf( "%i %irn", i, j );
auto f = []( int a, int b ) -> int {
return a * b;
};
decltype( f ) g = f; // the type of a lambda
function is unique and unnamed
i = f( 2, 2 );
j = g( 3, 3 );
printf( "%i %irn", i, j );
std::cout << add2( 2, 3 ) << std::endl;
}
37
3 6
4 9
5
Alternative function syntax
 In C++03 this is disallowed.
template<class Lhs, class Rhs>
Ret adding_func(const Lhs &lhs, const Rhs &rhs) {return
lhs + rhs;} //Ret must be the type of lhs+rhs
 Even with the aforementioned C++11 functionality
of decltype, this is not possible:
template<class Lhs, class Rhs>
decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs
&rhs) {return lhs + rhs;} //Not legal C++11
38
trailing-return-type
 To work around this, C++11 introduced a new function
declaration syntax, with a trailing-return-type:
template<class Lhs, class Rhs>
auto adding_func(const Lhs &lhs, const Rhs &rhs) ->
decltype(lhs+rhs) {return lhs + rhs;}
 This syntax can be used for more mundane function
declarations and definitions.
struct SomeStruct {
auto func_name(int x, int y) -> int;
};
auto SomeStruct::func_name(int x, int y) -> int {
return x + y;
}
39
Range-based for loop
 C++11 extends the syntax of the for statement to allow for
easy iteration over a range of elements.
int my_array[5] = {1, 2, 3, 4, 5};
// double the value of each element in my_array:
for (int &x : my_array) {
x *= 2;
}
// similar but also using type inference for array elements
for (auto &x : my_array) {
x *= 2;
}
 It will work for C-style arrays, initializer lists, and any type that
has begin() and end() functions defined for it that return iterators.
40
my own container can be used in range-based for loop
template<class T>
class MyVector {
public:
typedef T* iterator;
public:
T m_data[ 100 ];
int m_begin;
int m_end;
MyVector();
T& operator[]( int i ) { return m_data[ i ]; }
void push_back( T& d );
T* begin();
T* end();
};//class MyVector
41
class CData {
int data;
public:
CData( int d = 0 ) : data(d) {}
void DoIt() { printf( "data=%dn", data ); }//DoIt()
};//class CTest
template<class T>
MyVector<T>::MyVector() {
m_begin = 0;
m_end = 0;
}
template<class T>
void MyVector<T>::push_back( T& d ) {
m_data[ m_end++ ] = d;
}
template<class T>
T* MyVector<T>::begin() {
return &m_data[ m_begin ];
}
template<class T>
T* MyVector<T>::end() {
return &m_data[ m_end ];
}
42
void main() {
CData d1( 1 ), d2( 2 ), d3( 3 );
MyVector<CData> vec;
vec.push_back( d1 );
vec.push_back( d2 );
vec.push_back( d3 );
vec[ 1 ].DoIt();
for( CData& d : vec ) {
d.DoIt();
}
}//main()
Lambda functions and expressions
 C++11 provides the ability to create anonymous functions,
called lambda functions. These are defined as follows:
[](int x, int y) -> int { return x + y; }
 The return type of lambda can be omitted as long as
all return expressions return the same type. A lambda can
optionally be a closure.
43
when to use
int CompFunc( int left_, int right_ ) {
return left_ < right_;
}
class KCompare {
public:
int operator()( int left_, int right_ ) const {
return left_ < right_;
}
};
template<typename T>
void CompareTest( int a, int b, T predicate_ ) {
//const bool bCompResult = predicate_.operator()(a, b);
const bool bCompResult = predicate_( a, b );
printf( "CompareTest result = %drn", bCompResult );
}
int main() {
CompareTest( 2, 3, CompFunc );
CompareTest( 2, 3, KCompare() );
}
44
template<typename T>
void CompareTest( int a, int b, T predicate_ ) {
//const bool bCompResult = predicate_.operator()(a, b);
const bool bCompResult = predicate_( a, b );
printf( "CompareTest result = %drn", bCompResult );
}
int main() {
auto compareLambda = []( int a, int b )->int {return a < b; };
CompareTest( 2, 3, compareLambda );
CompareTest( 2, 3, []( int a, int b )->int {return a < b; } );
}
45
capture list
[capture](parameters) -> return_type { function_body }
[] //no variables defined. Attempting to use any external
variables in the lambda is an error.
[x, &y] //x is captured by value, y is captured by reference
[&] //any external variable is implicitly captured by reference if
used
[=] //any external variable is implicitly captured by value if used
[&, x] //x is explicitly captured by value. Other variables will be
captured by reference
[=, &z] //z is explicitly captured by reference. Other variables will
be captured by value
46
int main() {
std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
std::for_each( begin( some_list ), end( some_list ), [&total]( int x ) { total += x; } );
printf( "%irn", total );
}
47
class KTest {
public:
int some_func() const { return 2; }
void Test() {
std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
int value = 5;
std::for_each( begin( some_list ), end( some_list ), [&, value, this]( int x ) {
total += x * value * this->some_func();
} );
}
};
 This will cause total to be stored as a reference, but value will
be stored as a copy.
 The capture of this is special. It can only be captured by
value, not by reference. this can only be captured if the
closest enclosing function is a non-static member function.
 A lambda expression with an empty capture specification ([])
can be implicitly converted into a function pointer with the
same type as the lambda was declared with.
auto a_lambda_func = [](int x) { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //calls the lambda.
48
various usage of lambda
std::function<double( double )> f0 = []( double x ) {return 1; };
auto f1 = []( double x ) {return x; };
decltype( f0 ) fa[ 3 ] = { f0, f1, []( double x ) {return x*x; } };
std::vector<decltype( f0 )> fv = { f0, f1 };
fv.push_back( []( double x ) {return x*x; } );
for( int i = 0; i<fv.size(); i++ )
std::cout << fv[ i ]( 2.0 ) << std::endl;
for( int i = 0; i<3; i++ )
std::cout << fa[ i ]( 2.0 ) << std::endl;
for( auto &f : fv )
std::cout << f( 2.0 ) << std::endl;
for( auto &f : fa )
std::cout << f( 2.0 ) << std::endl;
std::cout << eval( f0 ) << std::endl;
std::cout << eval( f1 ) << std::endl;
std::cout << eval( []( double x ) {return x*x; } ) << std::endl;
49
Object construction improvement
 In C++03, constructors of a class are not allowed to call other
constructors of that class.
 C++11 allows constructors to call other peer constructors
(termed delegation).
class SomeType {
int number;
public:
SomeType(int new_number) : number(new_number) {}
SomeType() : SomeType(42) {}
};
50
 For member initialization, C++11 allows this syntax:
class SomeClass {
public:
SomeClass() {}
explicit SomeClass(int new_value) : value(new_value) {}
private:
int value = 5;
};
51
Explicit overrides and final
 In C++03, it is possible to accidentally create a new virtual
function, when one intended to override a base class function.
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int);
};
 Because it has a different signature, it creates a second virtual
function.
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int) override; // ill-formed - doesn't override a base
class method
};
52
 C++11 also adds the ability to prevent inheriting from classes
or simply preventing overriding methods in derived classes.
This is done with the special identifier final.
struct Base1 final { };
struct Derived1 : Base1 { }; // 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
};
53
Null pointer constant
 Since the dawn of C in 1972, the constant 0 has had the
double role of constant integer and null pointer constant.
 The ambiguity inherent in the double meaning of 0 was dealt
with in C by using the preprocessor macro NULL, which
commonly expands to either ((void*)0) or 0.
void foo(char *);
void foo(int);
 If NULL is defined as 0, the statement foo(NULL); will call
foo(int), which is almost certainly not what the programmer
intended.
 C++11 corrects this by introducing a new keyword to serve as
a distinguished null pointer constant: nullptr. It is of
type nullptr_t, which is implicitly convertible and comparable
to any pointer type or pointer-to-member type.
54
class KPointer {
public:
template<typename T>
KPointer& operator=( T rhs ) = delete;
KPointer& operator=( char* rhs ) {
m_pData = rhs;
return *this;
}
// do not use like this. it's just example.
KPointer& operator=( nullptr_t rhs ) {
delete m_pData;
m_pData = nullptr;
return *this;
}
public:
char* m_pData;
};
55
int main() {
KPointer t;
t = new char;
//t = 0; // compile time error!
t = nullptr;
return 0;
}
Strongly typed enumerations
 In C++03, enumerations are not type-safe.
 They are effectively integers, even when the enumeration
types are distinct.
 This allows the comparison between two enum values of
different enumeration types.
 The underlying integral type is implementation-defined.
 C++11 allows a special classification of enumeration that has
none of these issues. This is expressed using the enum class.
56
enum class Enumeration {
Val1,
Val2,
Val3 = 100,
Val4 // = 101
};
 This enumeration is type-safe. Enum class values are not
implicitly converted to integers. Thus, they cannot be
compared to integers either.
 The underlying type of enum classes is always known. The
default type is int; this can be overridden to a different
integral type.
enum class Enum2 : unsigned int {Val1, Val2};
57
Right angle bracket
 C++03's parser defines “>>” as the right shift operator in all
cases.
 C++11 improves the specification of the parser so that
multiple right angle brackets will be interpreted as closing the
template argument list where it is reasonable.
template<bool Test> class SomeType;
std::vector<SomeType<1>2>> x1; /* Interpreted as a std::vector of
SomeType<true>, followed by "2 >> x1", which is not legal syntax for a
declarator. 1 is true. */
58
Explicit conversion operators
 C++98 added the explicit keyword as a modifier on
constructors to prevent single-argument constructors from
being used as implicit type conversion operators.
 However, this does nothing for actual conversion operators.
 For example, a smart pointer class may have an operator
bool() to allow it to act more like a primitive pointer: if it
includes this conversion, it can be tested with if
(smart_ptr_variable) (which would be true if the pointer
was non-null and false otherwise).
 However, this allows other, unintended conversions as well.
 (We will look into more detail later in this presentation).
59
Template aliases
 In C++03, it is not possible to create a typedef template.
template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
typedef SomeType<OtherType, Second, 5> TypedefName; // Illegal in C++03
 C++11 adds this ability with this syntax.
template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
using TypedefName = SomeType<OtherType, Second, 5>;
 The using syntax can be also used as type aliasing in C++11:
typedef void (*FunctionType)(double); // Old style
using FunctionType = void (*)(double); // New introduced syntax
60
Variadic templates
 C++11 allows template definitions to take an arbitrary
number of arguments of any type.
template<typename... Values> class tuple;
 The above template class tuple can be used like this:
tuple<int, std::vector<int>, std::map<<std::string>,
std::vector<int>>> some_instance_name;
61
ellipsis operator (…)
Probably the most famous function in both C & C++ to take advantage of this mechanism is
printf-function in C standard library:
int printf (const char* format, ... );
Ellipsis mechanism can also be used with preprocessor in a form of a macro. A macro taking
a variable number of parameters is called a variadic macro.
#define VARIADIC_MACRO(...)
In C++, this ellipsis operator got a new meaning in different context called exception
handling. The operator is used in catch blocks after try blocks:
try{
// Try block.
}
catch(...){
// Catch block.
}
62
now ellipsis (…) can be used in C++11 template
 The ellipsis (...) operator has two roles:
– When it occurs to the left of the name of a parameter, it declares a
parameter pack.
– Using the parameter pack, the user can bind zero or more arguments
to the variadic template parameters.
– When the ellipsis operator occurs to the right of a template or
function call argument, it unpacks the parameter packs into separate
arguments.
 Another operator used with variadic templates is the sizeof...-
operator. sizeof... operator can be used to determine the
amount of types given into a variadic template.
template<typename... Arguments>
class VariadicTemplate{
private:
static const unsigned short int size = sizeof...(Arguments); };
63
simple example: variadic function template
template<typename T>
T adder( T v ) {
return v;
}
template<typename T, typename... Args>
T adder( T first, Args... args ) {
return first + adder( args... );
}
void main() {
long sum = adder( 1, 2, 3, 8, 7 );
printf( "%irn", sum );
std::string s1 = "x", s2 = "aa", s3 = "bb", s4 = "yy";
std::string ssum = adder( s1, s2, s3, s4 );
printf( "%srn", ssum.c_str() );
}
64
variadic template version of printf()
void printf2( const char *s ) {
while( *s ) {
if( *s == '%' ) {
if( *( s + 1 ) == '%' ) {
++s;
} else {
throw std::runtime_error( "invalid format string: missing arguments" );
}
}
std::cout << *s++;
}
}
65
template<typename T, typename... Args>
void printf2( const char *s, T value, Args... args ) {
while( *s ) {
if( *s == '%' ) {
if( *( s + 1 ) == '%' ) {
++s;
} else {
std::cout << value;
s += 2; // this only works on 2 characters format strings ( %d, %f, etc ). Fails
miserably with %5.4f
printf2( s, args... ); // call even when *s == 0 to detect extra arguments
return;
}
}
std::cout << *s++;
}
}
66
variadic class template
template<bool B, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
template <typename... Args>
struct find_biggest;
// the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First> {
typedef First type;
};
template <typename First, typename... Args>
struct find_biggest<First, Args...> {
typedef typename conditional<
sizeof( First ) >= sizeof( typename find_biggest<Args...>::type )
, First, typename find_biggest<Args...>::type>::type type;
};
67
// the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...> {
static const int size = sizeof...( Args ) + 1;
typedef typename find_biggest<Args...>::type next;
typedef typename conditional< sizeof( First ) >= sizeof(next)
, First, next>::type type;
};
void main() {
find_biggest<char, long long, float, short>::type i;
printf( "%irn", sizeof( i ) ); // 8
printf( "%i %irn", sizeof( i ) // 5
, find_biggest<char, long long, float, short>::size );
}
68
New string literals
 It is also sometimes useful to avoid escaping strings manually,
particularly for using literals of XMLfiles, scripting languages,
or regular expressions.
 C++11 provides a raw string literal:
#include <stdio.h>
void main() {
char* p0 = R"(The String Data  Stuff " rn)";
char* p1 = R"delimiter(The String Data  Stuff " rn)delimiter";
printf( "%srn", p0 );
printf( "%srn", p1 );
}
69
Thread-local storage
 In addition to the existing static, dynamic and automatic.
 A new thread-local storage duration is indicated by the
storage specifier thread_local.
 Microsoft Visual Studio 2013 doesn't support thread_local,
instead you can use __declspec(thread).
70
we want to maintain g_pData for each thread. How?
#include <iostream>
#include <thread>
#include <windows.h>
int* g_pData = nullptr;
void foo( int i ) {
if( g_pData == nullptr ) {
g_pData = new int[ 11 ];
printf( "g_pData allocated %irn", i );
}
Sleep( 500 );
printf( "%irn", i );
if( g_pData != nullptr ) {
delete[] g_pData;
printf( "g_pData destroyed %irn", i );
}
}
71
int main() {
std::thread first( foo, 1 );
std::thread second( foo, 3 );
std::cout << "main, foo and foo now
execute concurrently...n";
// synchronize threads:
first.join(); // pauses until first finishes
second.join(); // pauses until second finishes
std::cout << "foo and bar completed.n";
return 0;
}
 If you want to maintain the single g_pData, you must add
thread safety features.
72
__declspec(thread) int* g_pData = nullptr;
void foo( int i ) {
if( g_pData == nullptr ) {
g_pData = new int[ 11 ];
printf( "g_pData allocated %irn", i );
}
Sleep( 500 );
printf( "%irn", i );
if( g_pData != nullptr ) {
delete[] g_pData;
printf( "g_pData destroyed %irn", i );
}
}
int main() {
std::thread first( foo, 1 );
std::thread second( foo, 3 );
std::cout << "main, foo and foo now execute concurrently...n";
73
// synchronize threads:
first.join(); // pauses until first finishes
second.join(); // pauses until second finishes
std::cout << "foo and bar completed.n";
return 0;
}
g_pData allocated 1
g_pData allocated 3
main, foo and foo now execute
concurrently...
1
g_pData destroyed 1
3
g_pData destroyed 3
foo and bar completed.
Explicitly defaulted and deleted special member function
 For classes that do not provide them for themselves:
 In C++03, the compiler provides, a default constructor, a copy
constructor, a copy assignment operator (operator=), and a
destructor. The programmer can override these defaults by
defining custom versions.
 C++11 allows the explicit defaulting and deleting of these
special member functions.
 The = delete specifier can be used to prohibit calling any
function, which can be used to disallow calling a member
function with particular parameters.
74
famous usage
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
class KData {
public:
KData( const KData& rhs ) = delete;
KData& operator=( const KData& rhs ) = delete;
KData( int i ) : m_iData{ i } {}
public:
int m_iData = 0;
};
int main() {
std::vector<KData> v;
v.push_back( { 1 } ); // will not be compiled!
return 0;
}
75
Type long long 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. It is guaranteed to be at least as large as a long int, and
have no fewer than 64 bits.
76
Static assertions
 The new utility introduces a new way to test assertions at
compile-time, using the new keyword static_assert.
template<class T>
struct Check {
static_assert(sizeof(int) <= sizeof(T), "T is not big enough!");
};
77
C++ standard library changes
 Threading facilities
 General-purpose smart pointers
 Wrapper reference
 Type traits for metaprogramming
78
Allow garbage collected implementations
 When someday, garbage collector added into the C++ library.
We need to tell to the garbage collector about that do not
delete 'p' pointer it will be reachable later in my code.
 To tell this, we need to call std::declare_reachable(p);.
 In previous example, if we do not call
std::declare_reachable(p);, the pointer 'p' to dynamic object
can be destroyed by the garbage collector due to there is no
live pointer to dynamic object by 'scrambling p' statement.
 To prevent this situation, we must tell to the garbage collector
about reachableness of pointer to dynamic object.
 std::declare_reachable() is used for this purpose.
79
int main() {
int * p = new int( 1 ); // dynamic object
std::declare_reachable( p );
p = (int*)( ( std::uintptr_t )p ^ UINTPTR_MAX ); // scrambling p
// dynamic object not reachable by any live safely-derived pointer
p = std::undeclare_reachable( (int*)( ( std::uintptr_t )p ^ UINTPTR_MAX ) );
// p is back again a safely-derived pointer to the dynamic object
std::cout << "p: " << *p << 'n';
delete p;
return 0;
}
80
General-purpose smart pointers
 std::shared_ptr
 std::weak_ptr
 std::unique_ptr
81
void 참조를 특화로 구현
82
template<class T> struct shared_ptr_traits
{
typedef T& reference;
};
template<> struct shared_ptr_traits<void>
{
typedef void reference;
};  void타입에 대한 reference가 가능하도록
템플릿 특화specialization을 사용하여 미리
구현해 둡니다.
 기타 type-trait에 대한 설명은 생략합니다.
shared_ptr: 생성자 구현
83
template<class T> class shared_ptr
{
public:
typedef shared_ptr<T> this_type;
typedef T value_type;
typedef T* pointer;
typedef typename shared_ptr_traits<T>::reference reference;
public:
shared_ptr(T * p = 0) : px(p), pn(0)
{
if( px != NULL )
pn = new int(1);
}
 생성자에서는 전달받은 raw pointer를
초기화합니다.
 참조 카운팅을 위한 메모리 할당을 하고,
참조 카운터를 1로 초기화합니다.
shared_ptr: 복사 생성자와 파괴자 구현
84
shared_ptr( const shared_ptr& right_ ) : px( 0 ), pn( 0 )
{
release();
px = right_.px;
pn = right_.pn;
if( px != NULL )
*pn += 1;
}
~shared_ptr()
{
release();
}
 복사 생성자는 먼저 이전에 할당되어 있는
리소스를 해제 합니다.
 새로운 리소스에 대한 참조를 설정하고,
참조 카운터를 증가시킵니다.
shared_ptr: operator=(), operator pointer()
85
shared_ptr& operator=( const shared_ptr& right_ )
{
release();
px = right_.px;
pn = right_.pn;
if( px != NULL )
*pn += 1;
return *this;
}
operator pointer() const
{
return px;
}
 대입 연산자는 복사 생성자와 거의 동일하게
구현합니다.
 타입에 대한 포인터 연산이 제대로
동작하도록 operator T*()를 정의합니다.
shared_ptr: release() 구현
86
void release()
{
if( px != NULL && *pn >= 1 )
{
*pn -= 1;
if( *pn == 0 )
{
delete px;
px = NULL;
delete pn;
pn = NULL;
}//if
}//if
px = NULL;
pn = NULL;
}
 release()는 먼저 참조 카운터를 감소합니다.
 참조 카운터가 0이되면, 실제 리소스를 해제
합니다.
shared_ptr: reset(), use_count() 구현
87
void reset()
{
release();
}
void reset(T * p)
{
release();
px = p;
pn = NULL;
if( px != NULL )
pn = new int(1);
}
int use_count() const { return *pn; }
 reset()은 해제 후 할당과 동일합니다.
 완성된 shared_ptr은 암시적 생성implicit
construction을 지원하지 않으므로,
reset()구현이 반드시 필요합니다.
 use_count()는 현재 참조 카운터를
리턴합니다.
shared_ptr: operator*(), operator->() 구현
88
reference operator*() const // never throws
{
return *px;
}
T* operator->() const // never throws
{
return px;
}
private:
T* px;
int* pn;
};//template<class T> class shared_ptr
 간접지정 연산자와 화살표 연산자가 제대로
동작하도록 함수를 작성합니다.
 void*에 대한 참조가 동작하도록 하기
위해서는 void에 대한 참조를 템플릿 특화로
미리 구현해 두어야 합니다.
main()에서 테스트
89
int main()
{
typedef shared_ptr<int> IntPtr;
IntPtr spInt = new int(3); // spInt.use_count() == 1
if( spInt != NULL )
{
std::cout << *spInt << std::endl; // 3
}//if
IntPtr spInt2 = spInt; // spInt.use_count() == 2
IntPtr spInt3 = spInt; // spInt.use_count() == 3
spInt.reset( new int(4) ); // spInt.use_count() == 1
*spInt = 5; // 3 changed to 5
if( spInt2 != NULL ) // spInt2.use_count() == 2
{
std::cout << *spInt2 << std::endl; // 3
}//if
return 0;
}//int main()
copy-and-swap: swap() 메서드 구현
90
void swap( shared_ptr<T>& right_ ) // never throws
{
std::swap( px, right_.px );
std::swap( pn, right_.pn );
}
 exception safety
1) Basic: component의 invariant는 보존되고, resource
leak은 발생하지 않아야 합니다.
2) Strong: 성공적으로 완료되었던지 예외를 던졌던지 둘
중의 하나여야 합니다.
3) No-throw: 예외를 던지지 않아야 합니다.
 copy-and-swap을 지원하기 위해서 shared_ptr의
swap()은 예외를 던지지 않도록 구현해야 합니다.
shared_ptr: swap()을 반영한 수정
91
shared_ptr& operator=( const shared_ptr& right_ )
{
//release();
//px = right_.px;
//pn = right_.pn;
//if( px != NULL )
// *pn += 1;
this_type(right_).swap(*this);
return *this;
}
void reset(T * p)
{
//release();
//px = p;
//pn = NULL;
//if( px != NULL )
// pn = new int(1);
this_type(p).swap(*this);
}
관찰: if의 조건문 표현식
92
class KBoolTest
{
public:
operator bool() const { return true; }
operator int() const { return 1; }
operator int*() const { return NULL; }
int GetValue() const { return 9; }
};
int main()
{
KBoolTest t;
if( t )
std::cout << t.GetValue() << std::endl;
return 0;
}//int main()
 if문의 조건은 일반적인 bool 표현식이 아닌 C가
허용하는 참인 조건식을 적을 수 있습니다.
 평가의 partial order의 순서는 bool  native
type  pointer의 순입니다.
safe bool idiom
93
//int* p = spInt; // (1)
//if( spInt < spInt ) // (2)
//{
//}  지금까지의 구현은 (1)과 (2)처럼 잘못된
사용이나, 의미없는 bool 표현식을 막지
못합니다.
template <typename T> void some_func(const T& t) {
if (t)
t->print();
}
 smart pointer T에 대해 이 문장이
동작하려면 T는 bool형에 대한 형 변환
연산자를 제공해야 합니다.
해결시도1: operator bool() 구현
94
class Testable {
bool ok_;
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool() const {
return ok_;
}
};  shared_ptr은 자신이 valid한 raw pointer를 가질 때, true를
리턴하는 operator bool()을 작성할 수 있습니다.
operator bool() cont.
95
test << 1; // (1)
int i=test; // (2)
Testable a;
AnotherTestable b;
if (a==b) { // (3)
}
if (a<b) { // (4)
}
 이 구현은 (1), (2) 같은 의미 없는
문장이나, (3), (4) 같은 의미 없는 bool
검사를 막지 못합니다.
해결시도2: operator void*()구현
96
operator void*() const {
return ok_==true ? this : 0;
}
 이 구현은 영리해 보이지만, 아래의 문장처럼
delete를 직접호출 할 수 있는 약점을 가집니다.
Testable test;
delete test;
해결시도3: nested class
97
class Testable {
bool ok_;
public:
explicit Testable(bool b=true):ok_(b) {}
class nested_class;
operator const nested_class*() const {
return ok_ ? reinterpret_cast<const nested_class*>(this) : 0;
}
};
Testable b1,b2;
if (b1==b2) {
}
if (b1<b2) {
}
 safe bool을 위한 nested class 구현 역시 의미없는 bool
검사를 막지 못합니다.
 이 문제를 해결하려면 포인터 형변환이 되지만, < 같은 비교
연산자를 지원하지 않는 데이터 타입을 사용하는 것입니다.
 흥미롭게도 멤버 함수에 대한 포인터가 그렇게 동작합니다!
최종 버전: safe bool idiom
98
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
 if-문장의 조건 표현식에 포인터가 사용될 수 있는
점을 이용하여, 함수 포인터를 리턴하는 연산자
함수를 정의합니다.
shared_ptr의 내부: unspecified_bool_type 사용
99
//operator pointer() const
//{
// return px;
//}
void unspecified_bool() const
{
}
typedef void (shared_ptr::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{
return px == 0 ? 0 : &shared_ptr::unspecified_bool;
}
 boost의 실제 코드는
unspecified_bool_type()을 사용합니다.
 C++ 표준 라이브러리 뿐만 아니라, 게임
엔진의 스마트 포인터 구현은 모두 이러한
기법을 사용합니다.
shared_ptr에 적용된 safe bool idiom
100
typedef shared_ptr<int> IntPtr;
IntPtr spInt = new int(3);
IntPtr spInt2 = spInt;
IntPtr spInt3 = spInt;
spInt.reset( new int(4) );
*spInt = 5;
if( spInt2 != NULL )
{
std::cout << *spInt << std::endl;
}//if
int* p = spInt; // (1) error
if( spInt2 < spInt3 ) // (2) error
{
}
 이제 (1)과 (2)같은 의미 없는
문장은 컴파일 시간 에러가
발생합니다.
implicit constructor문제 해결하기
101
void Test( shared_ptr<int> spInt_ )
{
}
int iData = 5;
Test( &iData );
 실제 포인터가 아닌, 포인터 표현식에 대한 shared_ptr
생성을 막을 필요가 있습니다.
 이 문제에 대한 해결방법은 명시적 생성만 가능하도록
클래스를 설계하는 것입니다.
explicit shared_ptr(T * p = 0) : px(p), pn(0)
{
if( px != NULL )
pn = new int(1);
}
Wrapper reference
 A wrapper reference is obtained from an instance of the
template class reference_wrapper.
 Wrapper references are similar to normal references (‘&’) of
the C++ language. To obtain a wrapper reference from any
object the function template std::ref is used.
102
#include <iostream>
// This function will obtain a reference to the parameter 'r' and increment it.
void func( int &r ) { r++; }
// Template function.
template<class F, class P> void g( F f, P t ) { f( t ); }
int main() {
int i = 0;
g( func, i ); // 'g<void (int &r), int>' is instantiated
// then 'i' will not be modified.
std::cout << i << std::endl; // Output -> 0
g( func, std::ref( i ) ); // 'g<void(int &r),reference_wrapper<int>>' is instantiated
// then 'i' will be modified.
std::cout << i << std::endl; // Output -> 1
}
103
Polymorphic wrappers for function objects
 Polymorphic wrappers for function objects are similar
to function pointers in semantics and syntax, but are less
tightly bound and can refer to anything which can be called
(function pointers, member function pointers, or functors)
whose arguments are compatible with those of the wrapper.
 The template class function was defined inside the
header <functional>, without needing any change to the C++
language.
104
#include <functional>
#include <iostream>
struct Foo {
Foo( int num ) : num_( num ) {}
void print_add( int i ) { std::cout << num_ + i << 'n'; }
int num_;
};
void print_num( int i ) {
std::cout << i << 'n';
}
struct PrintNum {
void operator()( int i ) const {
std::cout << i << 'n';
}
};
105
int main() {
// store a free function
std::function<void( int )> f_display = print_num;
f_display( -9 );
// store a lambda
std::function<void()> f_display_42 = []() { print_num( 42 ); };
f_display_42();
// store a call to a member function
using namespace std::placeholders;
const Foo foo( 314159 );
std::function<void( int )> f_add_display = std::bind( &Foo::print_add, foo, _1 );
f_add_display( 1 );
// store a call to a function object
std::function<void( int )> f_display_obj = PrintNum();
f_display_obj( 18 );
}
106
Type traits for metaprogramming
 Metaprogramming consists of creating a program that creates
or modifies another program (or itself). This can happen
during compilation or during execution.
107
template<int B, int N>
struct Pow {
// recursive call and recombination.
enum{ value = B*Pow<B, N-1>::value };
};
template< int B >
struct Pow<B, 0> {
// ''N == 0'' condition of termination.
enum{ value = 1 };
};
int quartic_of_three = Pow<3, 4>::value;
108
type traits
 Many algorithms can operate on different types of data;
C++'s templates support generic programming and make
code more compact and useful.
 Nevertheless it is common for algorithms to need information
on the data types being used. This information can be
extracted during instantiation of a template class using type
traits.
 Type traits can identify the category of an object and all the
characteristics of a class.
 They are defined in the new header <type_traits>.
109
// First way of operating.
template< bool B > struct Algorithm {
template<class T> static int do_it( T& a ) {
printf( "firstrn" );
return 0;
}
};
// Second way of operating.
template<> struct Algorithm<true> {
template<class T> static int do_it( T a ) {
printf( "secondrn" );
return 0;
}
};
110
// Instantiating 'elaborate' will automatically
// instantiate the correct way to operate.
template<class T>
int elaborate( T a ) {
return Algorithm<std::is_floating_point<T>::value>::do_it( a );
}
void main() {
elaborate( 1.0f ); // second
elaborate( 1 ); // first
}
References
 https://en.wikipedia.org/wiki/C++11
 http://eli.thegreenplace.net/2014/variadic-templates-in-c/
111

More Related Content

PDF
Dynamic C++ ACCU 2013
PDF
Dynamic C++ Silicon Valley Code Camp 2012
PPTX
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
PDF
Look Ma, “update DB to HTML5 using C++”, no hands! 
PDF
Vulkan 1.0 Quick Reference
PDF
The Ring programming language version 1.5.4 book - Part 8 of 185
PDF
04 - Qt Data
PDF
The Ring programming language version 1.5.3 book - Part 8 of 184
Dynamic C++ ACCU 2013
Dynamic C++ Silicon Valley Code Camp 2012
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
Look Ma, “update DB to HTML5 using C++”, no hands! 
Vulkan 1.0 Quick Reference
The Ring programming language version 1.5.4 book - Part 8 of 185
04 - Qt Data
The Ring programming language version 1.5.3 book - Part 8 of 184

What's hot (20)

PDF
HexRaysCodeXplorer: make object-oriented RE easier
PDF
HDTR images with Photoshop Javascript Scripting
PDF
The Ring programming language version 1.5.1 book - Part 7 of 180
PPT
iOS Development with Blocks
PDF
T3chFest2016 - Uso del API JavaScript de Photoshop para obtener fotos HDTR
PPTX
Return of c++
PDF
OpenVG 1.1 Reference Card
PPTX
Box2D with SIMD in JavaScript
PDF
05 - Qt External Interaction and Graphics
PPT
Using QString effectively
PDF
[2019-07] GraphQL in depth (serverside)
PDF
Qt Widget In-Depth
PPTX
Story of static code analyzer development
PDF
The Ring programming language version 1.5.3 book - Part 92 of 184
ZIP
PDF
[C++ gui programming with qt4] chap9
PDF
Racing To Win: Using Race Conditions to Build Correct and Concurrent Software
PDF
The Ring programming language version 1.9 book - Part 43 of 210
PDF
03 - Qt UI Development
PDF
Compose Async with RxJS
HexRaysCodeXplorer: make object-oriented RE easier
HDTR images with Photoshop Javascript Scripting
The Ring programming language version 1.5.1 book - Part 7 of 180
iOS Development with Blocks
T3chFest2016 - Uso del API JavaScript de Photoshop para obtener fotos HDTR
Return of c++
OpenVG 1.1 Reference Card
Box2D with SIMD in JavaScript
05 - Qt External Interaction and Graphics
Using QString effectively
[2019-07] GraphQL in depth (serverside)
Qt Widget In-Depth
Story of static code analyzer development
The Ring programming language version 1.5.3 book - Part 92 of 184
[C++ gui programming with qt4] chap9
Racing To Win: Using Race Conditions to Build Correct and Concurrent Software
The Ring programming language version 1.9 book - Part 43 of 210
03 - Qt UI Development
Compose Async with RxJS
Ad

Viewers also liked (20)

PPTX
Beginning direct3d gameprogrammingmath02_logarithm_20160324_jintaeks
PPTX
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
PPTX
Beginning direct3d gameprogramming01_20161102_jintaeks
PPTX
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
PPTX
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
PPTX
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
PPTX
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
PPTX
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
PPTX
Beginning direct3d gameprogrammingmath03_vectors_20160328_jintaeks
PPTX
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
PPTX
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
PPTX
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeks
PPTX
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
PPTX
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
PPTX
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
PPTX
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
PPT
Logarithm Problems
PPT
Power Point Project
PPT
65 properties of logarithm
Beginning direct3d gameprogrammingmath02_logarithm_20160324_jintaeks
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
Beginning direct3d gameprogramming01_20161102_jintaeks
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
Beginning direct3d gameprogrammingmath03_vectors_20160328_jintaeks
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeks
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
Logarithm Problems
Power Point Project
65 properties of logarithm
Ad

Similar to Beginning direct3d gameprogrammingcpp02_20160324_jintaeks (20)

PPT
Oops lecture 1
PPTX
Oops presentation
PPT
data Structure Lecture 1
PPT
PPT
C++totural file
PDF
C++ references
PPT
Sqlapi0.1
PPTX
Constructors and Destructors
PDF
C++ Programming
PPTX
constructors shailee.pptxhhhtyygdxixixxxxix
PPTX
C++11: Feel the New Language
PDF
C++ Interview Questions and Answers PDF By ScholarHat
PPT
Virtual Function and Polymorphism.ppt
PPTX
OOP - Lec 2 - Const in Classes by hasnat.pptx
PPTX
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
PPTX
Lecture 9_Classes.pptx
PDF
pyjamas22_ generic composite in python.pdf
PDF
22 scheme OOPs with C++ BCS306B_module2.pdfmodule2.pdf
PDF
data structure book in c++ and c in easy wording
Oops lecture 1
Oops presentation
data Structure Lecture 1
C++totural file
C++ references
Sqlapi0.1
Constructors and Destructors
C++ Programming
constructors shailee.pptxhhhtyygdxixixxxxix
C++11: Feel the New Language
C++ Interview Questions and Answers PDF By ScholarHat
Virtual Function and Polymorphism.ppt
OOP - Lec 2 - Const in Classes by hasnat.pptx
Lecture 3, c++(complete reference,herbet sheidt)chapter-13
Lecture 9_Classes.pptx
pyjamas22_ generic composite in python.pdf
22 scheme OOPs with C++ BCS306B_module2.pdfmodule2.pdf
data structure book in c++ and c in easy wording

More from JinTaek Seo (14)

PPTX
Neural network 20161210_jintaekseo
PPTX
05 heap 20161110_jintaeks
PPT
02 linked list_20160217_jintaekseo
PPTX
Hermite spline english_20161201_jintaeks
PPT
01 stack 20160908_jintaek_seo
PPTX
03 fsm how_toimplementai_state_20161006_jintaeks
PPTX
Beginning direct3d gameprogrammingmath01_primer_20160324_jintaeks
PPT
Boost pp 20091102_서진택
PPT
아직도가야할길 훈련 20090722_서진택
PPT
3ds maxscript 튜토리얼_20151206_서진택
PPT
Multithread programming 20151206_서진택
PPT
03동물 로봇그리고사람 public_20151125_서진택
PPT
20150605 홀트입양예비부모모임 서진택
PPT
Boost라이브러리의내부구조 20151111 서진택
Neural network 20161210_jintaekseo
05 heap 20161110_jintaeks
02 linked list_20160217_jintaekseo
Hermite spline english_20161201_jintaeks
01 stack 20160908_jintaek_seo
03 fsm how_toimplementai_state_20161006_jintaeks
Beginning direct3d gameprogrammingmath01_primer_20160324_jintaeks
Boost pp 20091102_서진택
아직도가야할길 훈련 20090722_서진택
3ds maxscript 튜토리얼_20151206_서진택
Multithread programming 20151206_서진택
03동물 로봇그리고사람 public_20151125_서진택
20150605 홀트입양예비부모모임 서진택
Boost라이브러리의내부구조 20151111 서진택

Recently uploaded (20)

PDF
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
PPTX
Safety Seminar civil to be ensured for safe working.
DOCX
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
PPTX
UNIT 4 Total Quality Management .pptx
PDF
PPT on Performance Review to get promotions
PDF
Human-AI Collaboration: Balancing Agentic AI and Autonomy in Hybrid Systems
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPTX
Internet of Things (IOT) - A guide to understanding
PDF
Unit I ESSENTIAL OF DIGITAL MARKETING.pdf
PPT
Project quality management in manufacturing
PPTX
UNIT-1 - COAL BASED THERMAL POWER PLANTS
PPTX
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
PDF
Well-logging-methods_new................
PPT
Mechanical Engineering MATERIALS Selection
PDF
Automation-in-Manufacturing-Chapter-Introduction.pdf
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
PDF
SM_6th-Sem__Cse_Internet-of-Things.pdf IOT
PDF
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PDF
Model Code of Practice - Construction Work - 21102022 .pdf
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
Safety Seminar civil to be ensured for safe working.
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
UNIT 4 Total Quality Management .pptx
PPT on Performance Review to get promotions
Human-AI Collaboration: Balancing Agentic AI and Autonomy in Hybrid Systems
CYBER-CRIMES AND SECURITY A guide to understanding
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
Internet of Things (IOT) - A guide to understanding
Unit I ESSENTIAL OF DIGITAL MARKETING.pdf
Project quality management in manufacturing
UNIT-1 - COAL BASED THERMAL POWER PLANTS
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
Well-logging-methods_new................
Mechanical Engineering MATERIALS Selection
Automation-in-Manufacturing-Chapter-Introduction.pdf
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
SM_6th-Sem__Cse_Internet-of-Things.pdf IOT
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
Model Code of Practice - Construction Work - 21102022 .pdf

Beginning direct3d gameprogrammingcpp02_20160324_jintaeks

  • 1. Beginning Direct3D Game Programming: C++11 Primer [email protected] Division of Digital Contents, DongSeo University. March 2016
  • 2. C++11  C++11 is a version of the standard for the programming language C++.  It was approved by International Organization for Standardization (ISO) on 12 August 2011, replacing C++03,[1] and superseded by C++14 on 18 August 2014.[2]  Although one of the design goals was to prefer changes to the libraries over changes to the core language,[4] C++11 does make several additions to the core language. 2
  • 3. Design goals  Maintain stability and compatibility with C++98 and possibly with C.  Prefer introducing new features via the standard library, rather than extending the core language.  Improve C++ to facilitate systems and library design, rather than introduce new features useful only to specific applications. 3
  • 4. Extensions to the C++ core language  Rvalue references and move constructors.  Extern template  Initializer lists  Uniform initializations  Type inference  Ranged-based for loop  Lambda functions and expressions  Alternative function syntax  Explicit override and final  Null pointer constant  Explicit conversion operator  … 4
  • 5. Rvalue references and move constructors  rvalues? as they often lie on the right side of an assignment.  In C++03 and before, temporaries were intended to never be modifiable and were considered to be indistinguishable from const T& types.  C++11 adds a new non-const reference type called an rvalue reference, identified by T&&.  This refers to temporaries that are permitted to be modified after they are initialized, for the purpose of allowing "move semantics". 5
  • 6.  If a std::vector<T> temporary is created or returned from a function, it can be stored only by creating a new std::vector<T> and copying all the rvalue's data into it.  If std::vector<T> is a C++03 version without a move constructor, then the copy constructor will be invoked with a const std::vector<T>&, incurring a significant memory allocation.  Move constructor not only forgoes the expense of a deep copy, but is safe and invisible. 6
  • 7. std::move(), perfect forwarding  For safety reasons, a named variable will never be considered to be an rvalue even if it is declared as such. To get an rvalue, the function template std::move() should be used.  Due to the nature of the wording of rvalue references, and to some modification to the wording for lvalue references (regular references), rvalue references allow developers to provide perfect function forwarding. 7
  • 8. basic concepts of rvalue class KTest { public: KTest() { std::cout << "constructorrn"; } KTest( const KTest& rhs ) { std::cout << "copy constructorrn"; } ~KTest() { std::cout << "destructorrn"; } }; 8
  • 9. KTest F( KTest t ) { return t; } void G( const KTest& t ) { std::cout << "lvalue ref G " << std::endl; } void G( KTest&& t ) { //KTest u = std::move( t ); //KTest u = t; std::cout << "rvalue ref G " << std::endl; } int main() { KTest t; KTest u = t; u = F( KTest() ); std::cout << "rnbefore call Grn"; G( KTest() ); } 9 constructor copy constructor constructor copy constructor destructor destructor before call G constructor lvalue ref G destructor destructor destructor
  • 10. KTest F( KTest t ) { return t; } void G( const KTest& t ) { std::cout << "lvalue ref G " << std::endl; } void G( KTest&& t ) { //KTest u = std::move( t ); //KTest u = t; std::cout << "rvalue ref G " << std::endl; } int main() { KTest t; KTest u = t; u = F( KTest() ); std::cout << "rnbefore call Grn"; G( KTest() ); } 10 constructor copy constructor constructor copy constructor destructor destructor before call G constructor rvalue ref G destructor destructor destructor
  • 11. KTest F( KTest t ) { return t; } void G( const KTest& t ) { std::cout << "lvalue ref G " << std::endl; } void G( KTest&& t ) { KTest u = std::move( t ); //KTest u = t; std::cout << "rvalue ref G " << std::endl; } int main() { KTest t; KTest u = t; u = F( KTest() ); std::cout << "rnbefore call Grn"; G( KTest() ); } 11 We want to call the move constructor of 'u'. A named variable will never be considered to be an rvalue even if it is declared as such. To get an rvalue, the function template std::move() should be used.
  • 12. move constructor struct A { std::string s; A() : s( "test" ) { std::cout << "constructor An"; } A( const A& o ) : s( o.s ) { std::cout << "copy constructor An"; } A( A&& o ) : s( std::move( o.s ) ) { std::cout << "move constructor An"; } }; A f( A a ) { return a; } struct B : public A { std::string s2; int n; }; B g( B b ) { return b; } 12 we expect below things in 'B': * implicit move constructor B::(B&&) * calls A's move constructor * calls s2's move constructor * and makes a bitwise copy of n * but in Visual Studio 2013, implicit functions do not call base class's corresponding functions.
  • 13. int main() { std::cout << "Trying to move An"; A a1 = f( A() ); // move-construct from rvalue temporary std::cout << "Before move, a1.s = " << a1.s << "n"; A a2 = std::move( a1 ); // move-construct from xvalue std::cout << "After move, a1.s = " << a1.s << "n"; std::cout << "Trying to move Bn"; B b1 = g( B() ); std::cout << "Before move, b1.s = " << b1.s << "n"; B b2 = std::move( b1 ); // calls implicit move ctor std::cout << "After move, b1.s = " << b1.s << "n"; } 13 Trying to move A constructor A move constructor A Before move, a1.s = test move constructor A After move, a1.s = Trying to move B constructor A copy constructor A Before move, b1.s = test copy constructor A After move, b1.s = test
  • 14. struct A { std::string s; A() : s( "test" ) { std::cout << "constructor An"; } A( const A& o ) : s( o.s ) { std::cout << "copy constructor An"; } A( A&& o ) : s( std::move( o.s ) ) { std::cout << "move constructor An"; } }; struct C : public A { std::string s2; int n; C() : A() { std::cout << "constructor Cn"; } C( const C& o ) : A( o ) { std::cout << "copy constructor Cn"; } C( C&& o ) : A( std::move( o ) ) { std::cout << "move constructor Cn"; } //C( C&& o ) : A( o ) { std::cout << "move constructor Cn"; } }; 14
  • 15. KTest u = t; differs from u = t; class KTest { public: KTest() { std::cout << "constructorrn"; } KTest( const KTest& rhs ) { std::cout << "copy constructorrn"; } ~KTest() { std::cout << "destructorrn"; } KTest& operator=( const KTest& rhs ) { std::cout << "operator=rn"; return *this; } }; int main() { KTest t; KTest u = t; KTest v; v = t; // this is same as v.operator=(t); }15 constructor copy constructor constructor operator= destructor destructor destructor
  • 16. real world example class MemoryBlock { public: explicit MemoryBlock( size_t length ) : _length( length ) , _data( new int[ length ] ) { std::cout << "In MemoryBlock(size_t). length = " << _length << "." << std::endl; } // Destructor. ~MemoryBlock() { std::cout << "In ~MemoryBlock(). length = " << _length << "."; if( _data != nullptr ) { std::cout << " Deleting resource."; // Delete the resource. delete[] _data; _data = nullptr; } std::cout << std::endl; } 16
  • 17. MemoryBlock( const MemoryBlock& other ) : _length( other._length ) , _data( new int[ other._length ] ) { std::cout << "In MemoryBlock(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; std::copy( other._data, other._data + _length, _data ); } MemoryBlock& operator=( const MemoryBlock& other ) { std::cout << "In operator=(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; if( this != &other ) { delete[] _data; _length = other._length; _data = new int[ _length ]; std::copy( other._data, other._data + _length, _data ); } return *this; }17
  • 18. // Move constructor. MemoryBlock( MemoryBlock&& other ) : _data( nullptr ) , _length( 0 ) { std::cout << "In MemoryBlock(MemoryBlock&&). length = " << other._length << ". Moving resource." << std::endl; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } 18
  • 19. // Move assignment operator. MemoryBlock& operator=( MemoryBlock&& other ) { std::cout << "In operator=(MemoryBlock&&). length = " << other._length << "." << std::endl; if( this != &other ) { // Free the existing resource. delete[] _data; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } return *this; } 19
  • 20. Modification to the definition of plain old data  In C++03, a class or struct must follow a number of rules for it to be considered a plain old data(POD) type.  Types that fit this definition produce object layouts that are compatible with C, and they could also be initialized statically.  if someone were to create a C++03 POD type and add a non- virtual member function, this type would no longer be a POD type.  C++11 relaxed several of the POD rules, by dividing the POD concept into two separate concepts:trivial and standard- layout. 20 A class with complex move and copy constructors may not be trivial, but it could be standard- layout and thus interop with C.
  • 21. trivial  it is legal to copy data around via memcpy, rather than having to use a copy constructor. ① Has a trivial default constructor. This may use the default constructor syntax(SomeConstructor() = default;). ② Has trivial copy and move constructors, which may use the default syntax. ③ Has trivial copy and move assignment operators, which may use the default syntax. ④ Has a trivial destructor, which must not be virtual. 21
  • 22. standard-layout  It orders and packs its members in a way that is compatible with C. ① It has no virtual functions ② It has no virtual base classes ③ All its non-static data members have the same access control (public, private, protected) ④ All its non-static data members, including any in its base classes, are in the same one class in the hierarchy ⑤ The above rules also apply to all the base classes and to all non-static data members in the class hierarchy ⑥ It has no base classes of the same type as the first defined non-static data member 22
  • 23. #include <type_traits> struct X { // It means that you want to use the compiler-generated version // of that function, so you don't need to specify a body. X() = default; }; struct Y { Y() {}; }; int main() { static_assert( std::is_trivial<X>::value, "X should be trivial" ); static_assert( std::is_pod<X>::value, "X should be POD" ); static_assert( !std::is_trivial<Y>::value, "Y should not be trivial" ); static_assert( !std::is_pod<Y>::value, "Y should not be POD" ); } 23
  • 24. Extern template  In C++03, the compiler must instantiate a template whenever a fully specified template is encountered in a translation unit.  If the template is instantiated with the same types in many translation units, this can dramatically increase compile times.  C++11 now provides this syntax: extern template class std::vector<MyClass>; 24
  • 25. Initializer lists  C++03 inherited the initializer-list feature from C. A struct or array is given a list of arguments in braces, in the order of the members' definitions in the struct. struct Object { float first; int second; }; Object scalar = {0.43f, 10}; //One Object, with first=0.43f and second=10 Object anArray[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; //An array of three Objects 25
  • 26.  C++03 allows initializer-lists only on structs and classes that conform to the Plain Old Data (POD) definition.  C++11 extends initializer-lists, so they can be used for all classes including standard containers like std::vector. class SequenceClass { public: SequenceClass(std::initializer_list<int> list); }; SequenceClass some_var = {1, 4, 5, 6};  This constructor is a special kind of constructor, called an initializer-list-constructor. Classes with such a constructor are treated specially during uniform initialization. 26
  • 27. first-class citizen  In programming language design, a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities.  The simplest scalar data types, such as integer and floating- point numbers, are nearly always first-class.  In C++, arrays is not first-class: they cannot be assigned as objects or passed as parameters to a subroutine.  For example, C++ doesn't supports array assignment, and when they are passed as parameters, only the position of their first element is actually passed—their size is lost. 27
  • 28.  The class std::initializer_list<> is a first-class C++11 standard library type.  However, they can be initially constructed statically by the C++11 compiler only via use of the {} syntax. void function_name(std::initializer_list<float> list); function_name({1.0f, -3.45f, -0.4f});  Standard containers can also be initialized in these ways: std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" }; std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" }); std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; 28
  • 29. My own initializer_list? 29 The initializer_list is a real type, it can be used in other places besides class constructors. Regular functions can take typed initializer lists as arguments. But! std::initializer_list is treated specially. So you can not create your own initializer_list.
  • 30. Uniform initialization  C++03 has a number of problems with initializing types. Several ways to do this exist, and some produce different results when interchanged.  For example, The traditional constructor syntax can look like a function declaration.  Only aggregates and POD types can be initialized with aggregate initializers (using SomeType var = {/*stuff*/};). 30
  • 31.  C++11 provides a syntax that allows for fully uniform type initialization that works on any object. struct BasicStruct { int x; double y; }; struct AltStruct { AltStruct(int x, double y) : x_{x}, y_{y} {} private: int x_; double y_; }; BasicStruct var1{5, 3.2}; AltStruct var2{2, 4.3}; 31 struct IdString { std::string name; int identifier; }; IdString get_string() { return {"foo", 42}; //Note the lack of explicit type. }
  • 32.  The following code will call the initializer list constructor, not the constructor of std::vector that takes a single size parameter and creates the vector with that size. std::vector<int> the_vec{4}; 32
  • 33. Type inference: decltype  In C++03 (and C), to use a variable, its type must be specified explicitly.  However, with the advent of template types and template metaprogramming techniques, the type of something, particularly the well-defined return value of a function, may not be easily expressed. 33
  • 34. well-defined  In mathematics, an expression is called well-defined if its definition assigns it a unique interpretation or value. Otherwise, the expression is said to be not well-defined .  A function is well-defined if it gives the same result when the representation of the input is changed without changing the value of the input.  For instance if f takes real numbers as input, and if f(0.5) does not equal f(1/2) then f is not well-defined. 34
  • 35.  C++11 allows this to be mitigated in two ways. First, the definition of a variable with an explicit initialization can use the auto keyword. auto some_strange_callable_type = std::bind(&some_function, _2, _1, some_object); auto other_variable = 5; for (std::vector<int>::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr) for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)  Further, the keyword decltype can be used to determine the type of expression at compile-time. int some_int; decltype(some_int) other_integer_variable = 5; 35
  • 36. when to use // will not compiled! template<typename T, typename U> decltype(T+U) add( T t, U u ) { return t + u; } template<typename T, typename U> auto add2( T t, U u ) -> decltype( t + u ) // return type depends on template parameters { return t + u; } 36
  • 37. template<typename T, typename U> auto add2( T t, U u ) -> decltype( t + u ) // return type depends on template parameters { return t + u; } int main() { printf( "%i %irn", i, j ); auto f = []( int a, int b ) -> int { return a * b; }; decltype( f ) g = f; // the type of a lambda function is unique and unnamed i = f( 2, 2 ); j = g( 3, 3 ); printf( "%i %irn", i, j ); std::cout << add2( 2, 3 ) << std::endl; } 37 3 6 4 9 5
  • 38. Alternative function syntax  In C++03 this is disallowed. template<class Lhs, class Rhs> Ret adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} //Ret must be the type of lhs+rhs  Even with the aforementioned C++11 functionality of decltype, this is not possible: template<class Lhs, class Rhs> decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} //Not legal C++11 38
  • 39. trailing-return-type  To work around this, C++11 introduced a new function declaration syntax, with a trailing-return-type: template<class Lhs, class Rhs> auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}  This syntax can be used for more mundane function declarations and definitions. struct SomeStruct { auto func_name(int x, int y) -> int; }; auto SomeStruct::func_name(int x, int y) -> int { return x + y; } 39
  • 40. Range-based for loop  C++11 extends the syntax of the for statement to allow for easy iteration over a range of elements. int my_array[5] = {1, 2, 3, 4, 5}; // double the value of each element in my_array: for (int &x : my_array) { x *= 2; } // similar but also using type inference for array elements for (auto &x : my_array) { x *= 2; }  It will work for C-style arrays, initializer lists, and any type that has begin() and end() functions defined for it that return iterators. 40
  • 41. my own container can be used in range-based for loop template<class T> class MyVector { public: typedef T* iterator; public: T m_data[ 100 ]; int m_begin; int m_end; MyVector(); T& operator[]( int i ) { return m_data[ i ]; } void push_back( T& d ); T* begin(); T* end(); };//class MyVector 41 class CData { int data; public: CData( int d = 0 ) : data(d) {} void DoIt() { printf( "data=%dn", data ); }//DoIt() };//class CTest
  • 42. template<class T> MyVector<T>::MyVector() { m_begin = 0; m_end = 0; } template<class T> void MyVector<T>::push_back( T& d ) { m_data[ m_end++ ] = d; } template<class T> T* MyVector<T>::begin() { return &m_data[ m_begin ]; } template<class T> T* MyVector<T>::end() { return &m_data[ m_end ]; } 42 void main() { CData d1( 1 ), d2( 2 ), d3( 3 ); MyVector<CData> vec; vec.push_back( d1 ); vec.push_back( d2 ); vec.push_back( d3 ); vec[ 1 ].DoIt(); for( CData& d : vec ) { d.DoIt(); } }//main()
  • 43. Lambda functions and expressions  C++11 provides the ability to create anonymous functions, called lambda functions. These are defined as follows: [](int x, int y) -> int { return x + y; }  The return type of lambda can be omitted as long as all return expressions return the same type. A lambda can optionally be a closure. 43
  • 44. when to use int CompFunc( int left_, int right_ ) { return left_ < right_; } class KCompare { public: int operator()( int left_, int right_ ) const { return left_ < right_; } }; template<typename T> void CompareTest( int a, int b, T predicate_ ) { //const bool bCompResult = predicate_.operator()(a, b); const bool bCompResult = predicate_( a, b ); printf( "CompareTest result = %drn", bCompResult ); } int main() { CompareTest( 2, 3, CompFunc ); CompareTest( 2, 3, KCompare() ); } 44
  • 45. template<typename T> void CompareTest( int a, int b, T predicate_ ) { //const bool bCompResult = predicate_.operator()(a, b); const bool bCompResult = predicate_( a, b ); printf( "CompareTest result = %drn", bCompResult ); } int main() { auto compareLambda = []( int a, int b )->int {return a < b; }; CompareTest( 2, 3, compareLambda ); CompareTest( 2, 3, []( int a, int b )->int {return a < b; } ); } 45
  • 46. capture list [capture](parameters) -> return_type { function_body } [] //no variables defined. Attempting to use any external variables in the lambda is an error. [x, &y] //x is captured by value, y is captured by reference [&] //any external variable is implicitly captured by reference if used [=] //any external variable is implicitly captured by value if used [&, x] //x is explicitly captured by value. Other variables will be captured by reference [=, &z] //z is explicitly captured by reference. Other variables will be captured by value 46
  • 47. int main() { std::vector<int> some_list{ 1, 2, 3, 4, 5 }; int total = 0; std::for_each( begin( some_list ), end( some_list ), [&total]( int x ) { total += x; } ); printf( "%irn", total ); } 47 class KTest { public: int some_func() const { return 2; } void Test() { std::vector<int> some_list{ 1, 2, 3, 4, 5 }; int total = 0; int value = 5; std::for_each( begin( some_list ), end( some_list ), [&, value, this]( int x ) { total += x * value * this->some_func(); } ); } };
  • 48.  This will cause total to be stored as a reference, but value will be stored as a copy.  The capture of this is special. It can only be captured by value, not by reference. this can only be captured if the closest enclosing function is a non-static member function.  A lambda expression with an empty capture specification ([]) can be implicitly converted into a function pointer with the same type as the lambda was declared with. auto a_lambda_func = [](int x) { /*...*/ }; void (* func_ptr)(int) = a_lambda_func; func_ptr(4); //calls the lambda. 48
  • 49. various usage of lambda std::function<double( double )> f0 = []( double x ) {return 1; }; auto f1 = []( double x ) {return x; }; decltype( f0 ) fa[ 3 ] = { f0, f1, []( double x ) {return x*x; } }; std::vector<decltype( f0 )> fv = { f0, f1 }; fv.push_back( []( double x ) {return x*x; } ); for( int i = 0; i<fv.size(); i++ ) std::cout << fv[ i ]( 2.0 ) << std::endl; for( int i = 0; i<3; i++ ) std::cout << fa[ i ]( 2.0 ) << std::endl; for( auto &f : fv ) std::cout << f( 2.0 ) << std::endl; for( auto &f : fa ) std::cout << f( 2.0 ) << std::endl; std::cout << eval( f0 ) << std::endl; std::cout << eval( f1 ) << std::endl; std::cout << eval( []( double x ) {return x*x; } ) << std::endl; 49
  • 50. Object construction improvement  In C++03, constructors of a class are not allowed to call other constructors of that class.  C++11 allows constructors to call other peer constructors (termed delegation). class SomeType { int number; public: SomeType(int new_number) : number(new_number) {} SomeType() : SomeType(42) {} }; 50
  • 51.  For member initialization, C++11 allows this syntax: class SomeClass { public: SomeClass() {} explicit SomeClass(int new_value) : value(new_value) {} private: int value = 5; }; 51
  • 52. Explicit overrides and final  In C++03, it is possible to accidentally create a new virtual function, when one intended to override a base class function. struct Base { virtual void some_func(float); }; struct Derived : Base { virtual void some_func(int); };  Because it has a different signature, it creates a second virtual function. struct Base { virtual void some_func(float); }; struct Derived : Base { virtual void some_func(int) override; // ill-formed - doesn't override a base class method }; 52
  • 53.  C++11 also adds the ability to prevent inheriting from classes or simply preventing overriding methods in derived classes. This is done with the special identifier final. struct Base1 final { }; struct Derived1 : Base1 { }; // 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 }; 53
  • 54. Null pointer constant  Since the dawn of C in 1972, the constant 0 has had the double role of constant integer and null pointer constant.  The ambiguity inherent in the double meaning of 0 was dealt with in C by using the preprocessor macro NULL, which commonly expands to either ((void*)0) or 0. void foo(char *); void foo(int);  If NULL is defined as 0, the statement foo(NULL); will call foo(int), which is almost certainly not what the programmer intended.  C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. 54
  • 55. class KPointer { public: template<typename T> KPointer& operator=( T rhs ) = delete; KPointer& operator=( char* rhs ) { m_pData = rhs; return *this; } // do not use like this. it's just example. KPointer& operator=( nullptr_t rhs ) { delete m_pData; m_pData = nullptr; return *this; } public: char* m_pData; }; 55 int main() { KPointer t; t = new char; //t = 0; // compile time error! t = nullptr; return 0; }
  • 56. Strongly typed enumerations  In C++03, enumerations are not type-safe.  They are effectively integers, even when the enumeration types are distinct.  This allows the comparison between two enum values of different enumeration types.  The underlying integral type is implementation-defined.  C++11 allows a special classification of enumeration that has none of these issues. This is expressed using the enum class. 56
  • 57. enum class Enumeration { Val1, Val2, Val3 = 100, Val4 // = 101 };  This enumeration is type-safe. Enum class values are not implicitly converted to integers. Thus, they cannot be compared to integers either.  The underlying type of enum classes is always known. The default type is int; this can be overridden to a different integral type. enum class Enum2 : unsigned int {Val1, Val2}; 57
  • 58. Right angle bracket  C++03's parser defines “>>” as the right shift operator in all cases.  C++11 improves the specification of the parser so that multiple right angle brackets will be interpreted as closing the template argument list where it is reasonable. template<bool Test> class SomeType; std::vector<SomeType<1>2>> x1; /* Interpreted as a std::vector of SomeType<true>, followed by "2 >> x1", which is not legal syntax for a declarator. 1 is true. */ 58
  • 59. Explicit conversion operators  C++98 added the explicit keyword as a modifier on constructors to prevent single-argument constructors from being used as implicit type conversion operators.  However, this does nothing for actual conversion operators.  For example, a smart pointer class may have an operator bool() to allow it to act more like a primitive pointer: if it includes this conversion, it can be tested with if (smart_ptr_variable) (which would be true if the pointer was non-null and false otherwise).  However, this allows other, unintended conversions as well.  (We will look into more detail later in this presentation). 59
  • 60. Template aliases  In C++03, it is not possible to create a typedef template. template <typename First, typename Second, int Third> class SomeType; template <typename Second> typedef SomeType<OtherType, Second, 5> TypedefName; // Illegal in C++03  C++11 adds this ability with this syntax. template <typename First, typename Second, int Third> class SomeType; template <typename Second> using TypedefName = SomeType<OtherType, Second, 5>;  The using syntax can be also used as type aliasing in C++11: typedef void (*FunctionType)(double); // Old style using FunctionType = void (*)(double); // New introduced syntax 60
  • 61. Variadic templates  C++11 allows template definitions to take an arbitrary number of arguments of any type. template<typename... Values> class tuple;  The above template class tuple can be used like this: tuple<int, std::vector<int>, std::map<<std::string>, std::vector<int>>> some_instance_name; 61
  • 62. ellipsis operator (…) Probably the most famous function in both C & C++ to take advantage of this mechanism is printf-function in C standard library: int printf (const char* format, ... ); Ellipsis mechanism can also be used with preprocessor in a form of a macro. A macro taking a variable number of parameters is called a variadic macro. #define VARIADIC_MACRO(...) In C++, this ellipsis operator got a new meaning in different context called exception handling. The operator is used in catch blocks after try blocks: try{ // Try block. } catch(...){ // Catch block. } 62
  • 63. now ellipsis (…) can be used in C++11 template  The ellipsis (...) operator has two roles: – When it occurs to the left of the name of a parameter, it declares a parameter pack. – Using the parameter pack, the user can bind zero or more arguments to the variadic template parameters. – When the ellipsis operator occurs to the right of a template or function call argument, it unpacks the parameter packs into separate arguments.  Another operator used with variadic templates is the sizeof...- operator. sizeof... operator can be used to determine the amount of types given into a variadic template. template<typename... Arguments> class VariadicTemplate{ private: static const unsigned short int size = sizeof...(Arguments); }; 63
  • 64. simple example: variadic function template template<typename T> T adder( T v ) { return v; } template<typename T, typename... Args> T adder( T first, Args... args ) { return first + adder( args... ); } void main() { long sum = adder( 1, 2, 3, 8, 7 ); printf( "%irn", sum ); std::string s1 = "x", s2 = "aa", s3 = "bb", s4 = "yy"; std::string ssum = adder( s1, s2, s3, s4 ); printf( "%srn", ssum.c_str() ); } 64
  • 65. variadic template version of printf() void printf2( const char *s ) { while( *s ) { if( *s == '%' ) { if( *( s + 1 ) == '%' ) { ++s; } else { throw std::runtime_error( "invalid format string: missing arguments" ); } } std::cout << *s++; } } 65
  • 66. template<typename T, typename... Args> void printf2( const char *s, T value, Args... args ) { while( *s ) { if( *s == '%' ) { if( *( s + 1 ) == '%' ) { ++s; } else { std::cout << value; s += 2; // this only works on 2 characters format strings ( %d, %f, etc ). Fails miserably with %5.4f printf2( s, args... ); // call even when *s == 0 to detect extra arguments return; } } std::cout << *s++; } } 66
  • 67. variadic class template template<bool B, class T, class F> struct conditional { typedef T type; }; template<class T, class F> struct conditional<false, T, F> { typedef F type; }; template <typename... Args> struct find_biggest; // the biggest of one thing is that one thing template <typename First> struct find_biggest<First> { typedef First type; }; template <typename First, typename... Args> struct find_biggest<First, Args...> { typedef typename conditional< sizeof( First ) >= sizeof( typename find_biggest<Args...>::type ) , First, typename find_biggest<Args...>::type>::type type; }; 67
  • 68. // the biggest of everything in Args and First template <typename First, typename... Args> struct find_biggest<First, Args...> { static const int size = sizeof...( Args ) + 1; typedef typename find_biggest<Args...>::type next; typedef typename conditional< sizeof( First ) >= sizeof(next) , First, next>::type type; }; void main() { find_biggest<char, long long, float, short>::type i; printf( "%irn", sizeof( i ) ); // 8 printf( "%i %irn", sizeof( i ) // 5 , find_biggest<char, long long, float, short>::size ); } 68
  • 69. New string literals  It is also sometimes useful to avoid escaping strings manually, particularly for using literals of XMLfiles, scripting languages, or regular expressions.  C++11 provides a raw string literal: #include <stdio.h> void main() { char* p0 = R"(The String Data Stuff " rn)"; char* p1 = R"delimiter(The String Data Stuff " rn)delimiter"; printf( "%srn", p0 ); printf( "%srn", p1 ); } 69
  • 70. Thread-local storage  In addition to the existing static, dynamic and automatic.  A new thread-local storage duration is indicated by the storage specifier thread_local.  Microsoft Visual Studio 2013 doesn't support thread_local, instead you can use __declspec(thread). 70
  • 71. we want to maintain g_pData for each thread. How? #include <iostream> #include <thread> #include <windows.h> int* g_pData = nullptr; void foo( int i ) { if( g_pData == nullptr ) { g_pData = new int[ 11 ]; printf( "g_pData allocated %irn", i ); } Sleep( 500 ); printf( "%irn", i ); if( g_pData != nullptr ) { delete[] g_pData; printf( "g_pData destroyed %irn", i ); } } 71 int main() { std::thread first( foo, 1 ); std::thread second( foo, 3 ); std::cout << "main, foo and foo now execute concurrently...n"; // synchronize threads: first.join(); // pauses until first finishes second.join(); // pauses until second finishes std::cout << "foo and bar completed.n"; return 0; }
  • 72.  If you want to maintain the single g_pData, you must add thread safety features. 72
  • 73. __declspec(thread) int* g_pData = nullptr; void foo( int i ) { if( g_pData == nullptr ) { g_pData = new int[ 11 ]; printf( "g_pData allocated %irn", i ); } Sleep( 500 ); printf( "%irn", i ); if( g_pData != nullptr ) { delete[] g_pData; printf( "g_pData destroyed %irn", i ); } } int main() { std::thread first( foo, 1 ); std::thread second( foo, 3 ); std::cout << "main, foo and foo now execute concurrently...n"; 73 // synchronize threads: first.join(); // pauses until first finishes second.join(); // pauses until second finishes std::cout << "foo and bar completed.n"; return 0; } g_pData allocated 1 g_pData allocated 3 main, foo and foo now execute concurrently... 1 g_pData destroyed 1 3 g_pData destroyed 3 foo and bar completed.
  • 74. Explicitly defaulted and deleted special member function  For classes that do not provide them for themselves:  In C++03, the compiler provides, a default constructor, a copy constructor, a copy assignment operator (operator=), and a destructor. The programmer can override these defaults by defining custom versions.  C++11 allows the explicit defaulting and deleting of these special member functions.  The = delete specifier can be used to prohibit calling any function, which can be used to disallow calling a member function with particular parameters. 74
  • 75. famous usage #include <iostream> #include <vector> #include <algorithm> #include <functional> class KData { public: KData( const KData& rhs ) = delete; KData& operator=( const KData& rhs ) = delete; KData( int i ) : m_iData{ i } {} public: int m_iData = 0; }; int main() { std::vector<KData> v; v.push_back( { 1 } ); // will not be compiled! return 0; } 75
  • 76. Type long long 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. It is guaranteed to be at least as large as a long int, and have no fewer than 64 bits. 76
  • 77. Static assertions  The new utility introduces a new way to test assertions at compile-time, using the new keyword static_assert. template<class T> struct Check { static_assert(sizeof(int) <= sizeof(T), "T is not big enough!"); }; 77
  • 78. C++ standard library changes  Threading facilities  General-purpose smart pointers  Wrapper reference  Type traits for metaprogramming 78
  • 79. Allow garbage collected implementations  When someday, garbage collector added into the C++ library. We need to tell to the garbage collector about that do not delete 'p' pointer it will be reachable later in my code.  To tell this, we need to call std::declare_reachable(p);.  In previous example, if we do not call std::declare_reachable(p);, the pointer 'p' to dynamic object can be destroyed by the garbage collector due to there is no live pointer to dynamic object by 'scrambling p' statement.  To prevent this situation, we must tell to the garbage collector about reachableness of pointer to dynamic object.  std::declare_reachable() is used for this purpose. 79
  • 80. int main() { int * p = new int( 1 ); // dynamic object std::declare_reachable( p ); p = (int*)( ( std::uintptr_t )p ^ UINTPTR_MAX ); // scrambling p // dynamic object not reachable by any live safely-derived pointer p = std::undeclare_reachable( (int*)( ( std::uintptr_t )p ^ UINTPTR_MAX ) ); // p is back again a safely-derived pointer to the dynamic object std::cout << "p: " << *p << 'n'; delete p; return 0; } 80
  • 81. General-purpose smart pointers  std::shared_ptr  std::weak_ptr  std::unique_ptr 81
  • 82. void 참조를 특화로 구현 82 template<class T> struct shared_ptr_traits { typedef T& reference; }; template<> struct shared_ptr_traits<void> { typedef void reference; };  void타입에 대한 reference가 가능하도록 템플릿 특화specialization을 사용하여 미리 구현해 둡니다.  기타 type-trait에 대한 설명은 생략합니다.
  • 83. shared_ptr: 생성자 구현 83 template<class T> class shared_ptr { public: typedef shared_ptr<T> this_type; typedef T value_type; typedef T* pointer; typedef typename shared_ptr_traits<T>::reference reference; public: shared_ptr(T * p = 0) : px(p), pn(0) { if( px != NULL ) pn = new int(1); }  생성자에서는 전달받은 raw pointer를 초기화합니다.  참조 카운팅을 위한 메모리 할당을 하고, 참조 카운터를 1로 초기화합니다.
  • 84. shared_ptr: 복사 생성자와 파괴자 구현 84 shared_ptr( const shared_ptr& right_ ) : px( 0 ), pn( 0 ) { release(); px = right_.px; pn = right_.pn; if( px != NULL ) *pn += 1; } ~shared_ptr() { release(); }  복사 생성자는 먼저 이전에 할당되어 있는 리소스를 해제 합니다.  새로운 리소스에 대한 참조를 설정하고, 참조 카운터를 증가시킵니다.
  • 85. shared_ptr: operator=(), operator pointer() 85 shared_ptr& operator=( const shared_ptr& right_ ) { release(); px = right_.px; pn = right_.pn; if( px != NULL ) *pn += 1; return *this; } operator pointer() const { return px; }  대입 연산자는 복사 생성자와 거의 동일하게 구현합니다.  타입에 대한 포인터 연산이 제대로 동작하도록 operator T*()를 정의합니다.
  • 86. shared_ptr: release() 구현 86 void release() { if( px != NULL && *pn >= 1 ) { *pn -= 1; if( *pn == 0 ) { delete px; px = NULL; delete pn; pn = NULL; }//if }//if px = NULL; pn = NULL; }  release()는 먼저 참조 카운터를 감소합니다.  참조 카운터가 0이되면, 실제 리소스를 해제 합니다.
  • 87. shared_ptr: reset(), use_count() 구현 87 void reset() { release(); } void reset(T * p) { release(); px = p; pn = NULL; if( px != NULL ) pn = new int(1); } int use_count() const { return *pn; }  reset()은 해제 후 할당과 동일합니다.  완성된 shared_ptr은 암시적 생성implicit construction을 지원하지 않으므로, reset()구현이 반드시 필요합니다.  use_count()는 현재 참조 카운터를 리턴합니다.
  • 88. shared_ptr: operator*(), operator->() 구현 88 reference operator*() const // never throws { return *px; } T* operator->() const // never throws { return px; } private: T* px; int* pn; };//template<class T> class shared_ptr  간접지정 연산자와 화살표 연산자가 제대로 동작하도록 함수를 작성합니다.  void*에 대한 참조가 동작하도록 하기 위해서는 void에 대한 참조를 템플릿 특화로 미리 구현해 두어야 합니다.
  • 89. main()에서 테스트 89 int main() { typedef shared_ptr<int> IntPtr; IntPtr spInt = new int(3); // spInt.use_count() == 1 if( spInt != NULL ) { std::cout << *spInt << std::endl; // 3 }//if IntPtr spInt2 = spInt; // spInt.use_count() == 2 IntPtr spInt3 = spInt; // spInt.use_count() == 3 spInt.reset( new int(4) ); // spInt.use_count() == 1 *spInt = 5; // 3 changed to 5 if( spInt2 != NULL ) // spInt2.use_count() == 2 { std::cout << *spInt2 << std::endl; // 3 }//if return 0; }//int main()
  • 90. copy-and-swap: swap() 메서드 구현 90 void swap( shared_ptr<T>& right_ ) // never throws { std::swap( px, right_.px ); std::swap( pn, right_.pn ); }  exception safety 1) Basic: component의 invariant는 보존되고, resource leak은 발생하지 않아야 합니다. 2) Strong: 성공적으로 완료되었던지 예외를 던졌던지 둘 중의 하나여야 합니다. 3) No-throw: 예외를 던지지 않아야 합니다.  copy-and-swap을 지원하기 위해서 shared_ptr의 swap()은 예외를 던지지 않도록 구현해야 합니다.
  • 91. shared_ptr: swap()을 반영한 수정 91 shared_ptr& operator=( const shared_ptr& right_ ) { //release(); //px = right_.px; //pn = right_.pn; //if( px != NULL ) // *pn += 1; this_type(right_).swap(*this); return *this; } void reset(T * p) { //release(); //px = p; //pn = NULL; //if( px != NULL ) // pn = new int(1); this_type(p).swap(*this); }
  • 92. 관찰: if의 조건문 표현식 92 class KBoolTest { public: operator bool() const { return true; } operator int() const { return 1; } operator int*() const { return NULL; } int GetValue() const { return 9; } }; int main() { KBoolTest t; if( t ) std::cout << t.GetValue() << std::endl; return 0; }//int main()  if문의 조건은 일반적인 bool 표현식이 아닌 C가 허용하는 참인 조건식을 적을 수 있습니다.  평가의 partial order의 순서는 bool  native type  pointer의 순입니다.
  • 93. safe bool idiom 93 //int* p = spInt; // (1) //if( spInt < spInt ) // (2) //{ //}  지금까지의 구현은 (1)과 (2)처럼 잘못된 사용이나, 의미없는 bool 표현식을 막지 못합니다. template <typename T> void some_func(const T& t) { if (t) t->print(); }  smart pointer T에 대해 이 문장이 동작하려면 T는 bool형에 대한 형 변환 연산자를 제공해야 합니다.
  • 94. 해결시도1: operator bool() 구현 94 class Testable { bool ok_; public: explicit Testable(bool b=true):ok_(b) {} operator bool() const { return ok_; } };  shared_ptr은 자신이 valid한 raw pointer를 가질 때, true를 리턴하는 operator bool()을 작성할 수 있습니다.
  • 95. operator bool() cont. 95 test << 1; // (1) int i=test; // (2) Testable a; AnotherTestable b; if (a==b) { // (3) } if (a<b) { // (4) }  이 구현은 (1), (2) 같은 의미 없는 문장이나, (3), (4) 같은 의미 없는 bool 검사를 막지 못합니다.
  • 96. 해결시도2: operator void*()구현 96 operator void*() const { return ok_==true ? this : 0; }  이 구현은 영리해 보이지만, 아래의 문장처럼 delete를 직접호출 할 수 있는 약점을 가집니다. Testable test; delete test;
  • 97. 해결시도3: nested class 97 class Testable { bool ok_; public: explicit Testable(bool b=true):ok_(b) {} class nested_class; operator const nested_class*() const { return ok_ ? reinterpret_cast<const nested_class*>(this) : 0; } }; Testable b1,b2; if (b1==b2) { } if (b1<b2) { }  safe bool을 위한 nested class 구현 역시 의미없는 bool 검사를 막지 못합니다.  이 문제를 해결하려면 포인터 형변환이 되지만, < 같은 비교 연산자를 지원하지 않는 데이터 타입을 사용하는 것입니다.  흥미롭게도 멤버 함수에 대한 포인터가 그렇게 동작합니다!
  • 98. 최종 버전: safe bool idiom 98 class Testable { bool ok_; typedef void (Testable::*bool_type)() const; void this_type_does_not_support_comparisons() const {} public: explicit Testable(bool b=true):ok_(b) {} operator bool_type() const { return ok_==true ? &Testable::this_type_does_not_support_comparisons : 0; } };  if-문장의 조건 표현식에 포인터가 사용될 수 있는 점을 이용하여, 함수 포인터를 리턴하는 연산자 함수를 정의합니다.
  • 99. shared_ptr의 내부: unspecified_bool_type 사용 99 //operator pointer() const //{ // return px; //} void unspecified_bool() const { } typedef void (shared_ptr::*unspecified_bool_type)() const; operator unspecified_bool_type() const // never throws { return px == 0 ? 0 : &shared_ptr::unspecified_bool; }  boost의 실제 코드는 unspecified_bool_type()을 사용합니다.  C++ 표준 라이브러리 뿐만 아니라, 게임 엔진의 스마트 포인터 구현은 모두 이러한 기법을 사용합니다.
  • 100. shared_ptr에 적용된 safe bool idiom 100 typedef shared_ptr<int> IntPtr; IntPtr spInt = new int(3); IntPtr spInt2 = spInt; IntPtr spInt3 = spInt; spInt.reset( new int(4) ); *spInt = 5; if( spInt2 != NULL ) { std::cout << *spInt << std::endl; }//if int* p = spInt; // (1) error if( spInt2 < spInt3 ) // (2) error { }  이제 (1)과 (2)같은 의미 없는 문장은 컴파일 시간 에러가 발생합니다.
  • 101. implicit constructor문제 해결하기 101 void Test( shared_ptr<int> spInt_ ) { } int iData = 5; Test( &iData );  실제 포인터가 아닌, 포인터 표현식에 대한 shared_ptr 생성을 막을 필요가 있습니다.  이 문제에 대한 해결방법은 명시적 생성만 가능하도록 클래스를 설계하는 것입니다. explicit shared_ptr(T * p = 0) : px(p), pn(0) { if( px != NULL ) pn = new int(1); }
  • 102. Wrapper reference  A wrapper reference is obtained from an instance of the template class reference_wrapper.  Wrapper references are similar to normal references (‘&’) of the C++ language. To obtain a wrapper reference from any object the function template std::ref is used. 102
  • 103. #include <iostream> // This function will obtain a reference to the parameter 'r' and increment it. void func( int &r ) { r++; } // Template function. template<class F, class P> void g( F f, P t ) { f( t ); } int main() { int i = 0; g( func, i ); // 'g<void (int &r), int>' is instantiated // then 'i' will not be modified. std::cout << i << std::endl; // Output -> 0 g( func, std::ref( i ) ); // 'g<void(int &r),reference_wrapper<int>>' is instantiated // then 'i' will be modified. std::cout << i << std::endl; // Output -> 1 } 103
  • 104. Polymorphic wrappers for function objects  Polymorphic wrappers for function objects are similar to function pointers in semantics and syntax, but are less tightly bound and can refer to anything which can be called (function pointers, member function pointers, or functors) whose arguments are compatible with those of the wrapper.  The template class function was defined inside the header <functional>, without needing any change to the C++ language. 104
  • 105. #include <functional> #include <iostream> struct Foo { Foo( int num ) : num_( num ) {} void print_add( int i ) { std::cout << num_ + i << 'n'; } int num_; }; void print_num( int i ) { std::cout << i << 'n'; } struct PrintNum { void operator()( int i ) const { std::cout << i << 'n'; } }; 105
  • 106. int main() { // store a free function std::function<void( int )> f_display = print_num; f_display( -9 ); // store a lambda std::function<void()> f_display_42 = []() { print_num( 42 ); }; f_display_42(); // store a call to a member function using namespace std::placeholders; const Foo foo( 314159 ); std::function<void( int )> f_add_display = std::bind( &Foo::print_add, foo, _1 ); f_add_display( 1 ); // store a call to a function object std::function<void( int )> f_display_obj = PrintNum(); f_display_obj( 18 ); } 106
  • 107. Type traits for metaprogramming  Metaprogramming consists of creating a program that creates or modifies another program (or itself). This can happen during compilation or during execution. 107
  • 108. template<int B, int N> struct Pow { // recursive call and recombination. enum{ value = B*Pow<B, N-1>::value }; }; template< int B > struct Pow<B, 0> { // ''N == 0'' condition of termination. enum{ value = 1 }; }; int quartic_of_three = Pow<3, 4>::value; 108
  • 109. type traits  Many algorithms can operate on different types of data; C++'s templates support generic programming and make code more compact and useful.  Nevertheless it is common for algorithms to need information on the data types being used. This information can be extracted during instantiation of a template class using type traits.  Type traits can identify the category of an object and all the characteristics of a class.  They are defined in the new header <type_traits>. 109
  • 110. // First way of operating. template< bool B > struct Algorithm { template<class T> static int do_it( T& a ) { printf( "firstrn" ); return 0; } }; // Second way of operating. template<> struct Algorithm<true> { template<class T> static int do_it( T a ) { printf( "secondrn" ); return 0; } }; 110 // Instantiating 'elaborate' will automatically // instantiate the correct way to operate. template<class T> int elaborate( T a ) { return Algorithm<std::is_floating_point<T>::value>::do_it( a ); } void main() { elaborate( 1.0f ); // second elaborate( 1 ); // first }

Editor's Notes

  • #36: This type is easily determined procedurally by the compiler as part of its semantic analysis duties, but is not easy for the user to determine upon inspection.
  • #48: This will cause total to be stored as a reference, but value will be stored as a copy. The capture of this is special. It can only be captured by value, not by reference. this can only be captured if the closest enclosing function is a non-static member function.