milot shala - c++ (oscal2014)
DESCRIPTION
In this talk most of the C++11 features will be uncovered and examples from real world use will be presented from my personal experience in writing software systems using C++11 using GCC compiler. Also I will compare open source implementation with proprietary implementation of C++11. This is basically a C++11 talk to give audience a glimpse on what is going on in the C++ world.TRANSCRIPT
C++11
Implementa-on differences between proprietary and open source compilers
and walkthrough on what’s new
if (myself != nullptr)
• Milot Shala • Primarily wri-ng soEware in C++ for quite some -me
• Been in the industry for almost 13 years now • Worked on cool and innova-ve projects • Built a cross-‐plaMorm library that had to work with MicrosoE’s Visual C++ compiler
Beginning of C++11 and Visual C++ compiler == nightmare
I wrote two crazy template classes // List template class to “keep” reference count !template<class T> class List { ! !}; !!// Window template template class with it’s constructor !template<class W, class H, template <typename> class L> class Window { !public: ! Window() { ! auto references = new L<W>(); ! } !
"!"//...!
} !
Let me walk you through new changes
Window<int, int, List>* window = new Window<int, int, List>(); Before:
auto window = new Window<int, int, List>(); AEer:
Let me walk you through new changes
Imagine a piece of code like this:
std::vector<Window<int, int, List> >* vec = new std::vector<Window<int, int, List> >(); !!for (std::vector<Window<int, int, List> >::iterator it_begin = vec->begin(); ! it_begin != vec->end(); ++it_begin) { ! // iterate!}
Was replaced with this:
auto vec1 = new std::vector<Window<int, int, List> >(); !!for (auto win : *vec1) { ! // iterate!}
Smart Pointers Window<int, int, List>* window = new Window<int, int, List>();
Not as easy as it looks! Who should delete this object?
std::shared_ptr<Window<int, int, List> > window(new Window<int, int, List>());
We can use shared_ptr or unique_ptr
Or beWer this: auto window = std::make_shared<Window<int, int, List> >();
std::unique_ptr!std::shared_ptr
From the list of 41 entries I extracted only features not yet implemented _today_ in Visual C++ and are implemented in g++
Feature Visual C++ 2013
g++ 4.8.1
sizeof on non-‐sta-c data members without an instance
No Yes
Changed restric-ons on union members
No Yes
User defined literals
No Yes
Encoding support in literals
No Yes
Feature Visual C++ 2013
g++ 4.8.1
Template aliases
No Yes
Defaulted methods
No Yes
Deleted methods
No Yes
Generalized aWributes
No Yes
New built-‐in types
Par-al Yes
Alignment support
Par-al Yes
Inline namespaces
No Yes
Feature Visual C++ 2013
g++ 4.8.1
Arbitrary expressions in template deduc-on contexts
No Yes
Non-‐sta-c data member ini-alizers
No Yes
noexcept No Yes
constexpr No Yes
Thread local storage
Par-al Yes
Inheri-ng constructors
No Yes
Rvalue references for *this
No Yes
C++ Template Meta-‐Programming
• Compile-‐-me results • Can be used in gaming, e.g. calculate gravity equa-on and have the value ready
• Not easy! Typical func-on to calculate Fibonacci
int fibonacci(int n) !{ ! if (n <= 2) { " "! return 1; ! } else { ! return fibonacci(n - 1) + fibonacci(n - 2); ! } !}
C++ Template Meta-‐Programming template <int T> struct Fibonacci !{ ! enum { value = (Fibonacci<T - 1>::value + Fibonacci<T - 2>::value) }; !}; !!template <> struct Fibonacci<0> !{ ! enum { value = 1 }; !}; !!template <> struct Fibonacci<1> !{ ! enum { value = 1 }; !}; !!template <> struct Fibonacci<2> !{ ! enum { value = 1 }; !};
Generalized constant expressions Bjarne Stroustrup is not good with words. He admiWed it himself!
All he means is this
constexpr int fibonacci (int n) !{ ! return (n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2)); !}
Calculates the Fibonacci sequence in compile-‐-me so the result is already there to be used.
Supports only a single line implementa-on.
And this is missing in Visual C++ compiler!
Variadic Templates
• C++ uses variable argument list (so does Java and C):
int avg( int n, ... ) !{ ! va_list pVarArg; ! va_start( pVarArg, n ); ! ! // ...!}
• Now we use similar approach with templates and it’s arguments
// usage!int i = avg(10, 10, 10, 10, 10);
Variadic Templates
• Why we need them? • std::pair pairs two items together • std::tuple pairs zero or more items together (feature achieved with variadic templates)
std::tuple<int, int, std::string> getWindowInformation(int id) !{ ! if (id == 0) return std::make_tuple(100, 100, "Settings"); ! if (id == 1) return std::make_tuple(800, 600, "Main Window"); ! if (id == 2) return std::make_tuple(800, 60, "Chat Window"); ! throw std::invalid_argument("id"); !}
We can use whatever we want!
Variadic Templates
• Usage
for (auto window : windows) { ! auto win = getWindowInformation(window); ! std::cout << "Window 0 - "! << "Width: " << std::get<0>(win) << ", "! << "Height: “ << std::get<1>(win) << ", "! << "Title: ” << std::get<2>(win) << '\n'; ! }
Variadic Templates basic implementa-on
template<class... elements> class tuple; !!// empty!template<> class tuple<> {}; !!template<class _class, class... elements> !class tuple<_class, elements...> : private tuple<elements...> !{ !public: ! _class _this; !};
Ellipsis just like in the variable argument lists!
Cool stuff about variadic templates
• This is how they can be used (16 arguments):
• In the beginning in Visual C++ maximum was 5 arguments only!
std::tuple<int, int, int, int, int, ! int, int, int, int, int, ! int, int, int, int, int, ! int, std::string> getWindowInformation(int id) !{ ! return std::make_tuple(100, 100, 100, ! 100, 100, 100, ! 100, 100, 100, ! 100, 100, 100, ! 100, 100, 100, ! 100,"Settings"); !}
A comment from MicrosoE kernel developer on the issue!
We just can't be fucked to implement C11 support, and variadic templates were just too hard to implement in a year. (But ohmygosh we turned "^" into a reference-‐counted pointer operator. Oh, and what's a reference cycle?) ~ Anonymous MicrosoE Employee on Reddit
Lvalues and Rvalues
• Lvalue can appear on both leE and right sides of the assignment operator
• Rvalue can appear only on the right side of an assignment operator
int i = 42; !i = 43; // lvalue!int* p = &i; // lvalue!!int& atlas(); !atlas() = 42; // lvalue!int* p1 = &atlas(); //lvalue
int stryder(); !int j = 0; !j = stryder(); // rvalue!int* p2 = &stryder(); // fail!j = 42; // rvalue
Cannot take address of rvalue reference
Move seman-cs Window<int, int, List> wnd(); !Window<int, int, List> x; !// use x...!x = wnd();
Destroy resource held by x
Last line will
Copy from temporary resource returned from
wnd()
Destroy temporary resource and release
the memory
Move Seman-cs
Original Object
COPY New copied object
Original Object
MOVE New object
We want to move! Even a child can move things around!
How the object assignment operator should be implemented?
// Classical implementation!Window& Window::operator=(Window const & rhs);!!// Move semantics: exchange content between this and wnd!Window& Window::operator=(Window&& wnd) { "!
"return *this; !}
// Another usage with std::move!std::string str = "Stand by for Titanfall!"; !std::vector<std::string> v; !!// Copy!v.push_back(str); ! !// Move!v.push_back(std::move(str));
Back to std::make_pair
// C++98!template <class T1, class T2> pair<T1,T2> make_pair (T1 x, T2 y);
// C++11!template <class T1, class T2> pair<V1,V2> make_pair (T1&& x, T2&& y);
What is the difference?
Rvalue references!
Back to std::make_pair
• C++11 flag was set on Visual C++ compiler op-on
• Code worked properly on g++ • I was gelng “You cannot bind an lvalue to an rvalue” error message!
• It was lacking proper overloaded method to support backward compa-bility
Had to hack my way into MicrosoE header files to trick it to compile!
Problem? • Worked on a corporate • Bureaucracy kills the mood • If you do something small will go unno-ced • You need to do something dras-c to get no-ced
• In open source community you just need to start doing it!
• Everyone will appreciate whatever you do! Even if it’s 5% speed increase or a -ny feature you will get appreciated!
Another comment from same guy
There's also liPle incenQve to create changes in the first place. On linux-‐kernel, if you improve the performance of directory traversal by a consistent 5%, you're praised and thanked. Here, if you do that and you're not on the object manager team, then even if you do get your code past the Ob owners and into the tree, your own management doesn't care. ~ Anonymous MicrosoE Employee
Thank you!
• Unfortunately the post was deleted from Reddit (yes MicrosoE reads Reddit).
• Fortunately someone copied it over to his blog:
hPp://bit.ly/milot