310 likes | 429 Views
Yaser Zhian Dead Mage 2012. C++11 – A Change in Style. If you write C-style code, you’ll end up with C-style bugs. -- Bjarne Stroustrup If you write Java-style code, you’ll have Java-level performance. Why C++?. C++ has no replacement if you want total control best performance/$
E N D
YaserZhian Dead Mage 2012 C++11 – A Change in Style
If you write C-style code, you’ll end up with C-style bugs. -- BjarneStroustrup If you write Java-style code, you’ll have Java-level performance. http://yaserzt.com/
Why C++? • C++ has no replacement if you want • total control • best performance/$ • to take advantage of hardware (multicore, GPU, …) • to program the way you want • zero-overhead abstractions http://yaserzt.com/
C++ History • C++98: First Standard • C++03: minor changes, mostly the standard • TR1 • C++11 • Larger and more complex • Leaner and meaner at the same time http://yaserzt.com/
C++: Il Buono, Il Brutto, Il Cattivo • Mixed-paradigm, statically-typed, compiled, widespread, many libraries, YDPFWYDU, works everywhere and with everything. • No ABI, tooling very complex. • Libraries don’t work together, complex and vast, bad teachers, intimidating first experience, seems too verbose and low-level. http://yaserzt.com/
C++11 Philosophy (sort of) • Oriented towards library-developers • Lower-cost abstractions • Easier for beginners (a little) • “If it can go into the Standard Library, do not put it in the language” • “Don’t break people’s code” http://yaserzt.com/
A Hurried and Incomprehensive Tour of Some Features of an Arbitrary Subset of C++11 http://yaserzt.com/
auto and decltype (1/2) • What is the type of a + b? • Even if you don’t know, the compiler always does. • decltype(a + b) c; • Instead of doublec; • auto instructs the compiler to infer type from initializing expression, e.g. • auto foo = a * b + c * d; • auto bar =newstd::map<std::string, bool>; http://yaserzt.com/
auto and decltype (2/2) • Not always a convenience feature. • What’s the return type oftemplate <typenameT, typenameU>??? Add (T const & a, U const & b){returna + b;} • One answer (not entirely correct) is decltype(T() + U()) • The correct answer is decltype(a + b) • But that won’t compile. • That’s the motivation behind the new function declaration syntax: • autoFun (type1p1, type2p2, ...) -> returntype • The above function then becomes: • template<typenameT, typenameU>autoAdd (T const & a, U const & b) -> decltype(a + b); http://yaserzt.com/
Lambdas (1/3) • Think of them as unnamed functions, written in the middle of your code, plus much more. • [] (inta, intb) -> int {returna + b;} • Lambdas are far-reaching and far more complicated under the hood, with many more features. • auto g = [] (inta, intb) -> int{returna + b;};intc = g(43, -1); • std::function<int (int, int)> h = [] (inta, intb) -> int {returna + b;}; http://yaserzt.com/
Lambdas (2/3) • std::for_each (v.begin(), v.end(), [](floatf) {std::cout << f << std::endl;}); • int x = 7;std::for_each (v.begin(), v.end(), [x](float & f) {f += x;}); • float sum = 0.0f;std::for_each (v.begin(), v.end(), [&sum](floatf) {sum += f;}); http://yaserzt.com/
Lambdas (3/3) • classStupidCollection{private:std::vector<int> m_data; • public: . . . • voidapply (std::function<int (int)> f) {for (autoi = m_data.begin(), e = m_data.end(); i != e; ++i)*i = f (*i); } • template<typenameFunc>void apply (Funcf) {for(auto i = m_data.begin(), e = m_data.end(); i != e; ++i)*i = f (*i); } • }; http://yaserzt.com/
Rvalue References and Moving (1/6) • C++ used to have a tendency to copy stuff around if you weren’t paying attention! • What happens when • vector<string> GenerateNames(){returnvector<string>(50, string(100, '*'));} • vector<string> vs = GenerateNames(); • All sorts of techniques and tricks to avoid those copies. • Hold that thought for a minute. http://yaserzt.com/
Rvalue References and Moving (2/6) • string s = string("Hello") + "world."; • this ultimately called the copy c’torstring(stringconst & that). • C++11 introduces “rvalue references” to let you work with (kinda) temporary objects. • Rvalue references are denoted with &&. • e.g. int && p = 3; • In situations where you used to copy the data from an object into another object, if your first object is an rvalue (i.e. temporary) now you can “move” the data from that to this. • Two important usages of rvalue references are “move construction” and “move assignment”. • e.g. string(string && that);// move c'tor • and string& operator = (string && that);// move assignment http://yaserzt.com/
Rvalue References and Moving (3/6) template <typename T> class Matrix { private: T * m_data; unsignedm_rows, m_columns; public: Matrix (unsigned rows, unsigned columns); ~Matrix (); Matrix (Matrix<T> const & that); template <typenameU> Matrix (Matrix<U> const & that); MyType & operator = (Matrix<T> const & that); Matrix (Matrix<T> && that); MyType& operator = (MyType && that); unsignedrows () const; unsignedcolumns () const; unsignedsize () const; T const & operator () (unsigned row, unsigned col) const; T & operator () (unsigned row, unsigned col);// m(5, 7) = 0; template<typenameU> autooperator + (Matrix<U> const & rhs) const-> Matrix<decltype(T() + U())>; template<typenameU> autooperator * (Matrix<U> const & rhs) const-> Matrix<decltype(T() * U() + T() * U())>; }; http://yaserzt.com/
Rvalue References and Moving (4/6) Matrix (unsigned rows, unsigned columns) : m_rows (rows), m_columns (columns), m_data (new T [rows * columns]) { } ~Matrix () { delete[] m_data; } Matrix (Matrix<T> const & that) : m_rows (that.m_rows), m_columns (that.m_columns), m_data (new T [that.m_rows * that.m_columns]) { std::copy (that.m_data, that.m_data + (m_rows * m_columns), m_data); } Matrix<T>& operator = (Matrix<T>const & that) { if(this != &that) { m_rows= that.m_rows; m_columns= that.m_columns; T * new_data= new T [m_rows* m_columns]; std::copy (that.m_data, that.m_data + (m_rows * m_columns), new_data); delete[] m_data; m_data = new_data; } return*this; } http://yaserzt.com/
Rvalue References and Moving (5/6) Matrix (Matrix<T> && that) : m_rows (that.m_rows), m_columns (that.m_columns), m_data (that.m_data) { that.m_rows= that.m_columns = 0; that.m_data= nullptr; } Matrix<T> & operator = (Matrix<T> && that) { if(this != &that) { T * old_data = m_data; m_rows= that.m_rows; m_columns= that.m_columns; m_data= that.data; that.m_rows= rhs.m_columns = 0; that.m_data= nullptr; delete[] old_data; } return*this; } http://yaserzt.com/
Rvalue References and Moving (6/6) structSomeClass { strings; vector<int> v; // WRONG! WRONG! WRONG! // Doesn’t move, just copies. SomeClass (SomeClass && that) : s (that.s) , v (that.v) {} SomeClass(SomeClass && that) : s (std::move(that.s)) , v (std::move(that.v)) {} }; http://yaserzt.com/
std::move (1/5) • In principle, std::move should look like this:template <typenameT>??? move (??? something){returnsomething;} • What should the argument type be? • T&& ? • T& ? • Both? Neither? • We need to be able to pass in both lvalues and rvalues. We need both. http://yaserzt.com/
std::move (2/5) • We can overload move() like this: • move (T && something) • move (T & something) • “Reference collapse” rule in C++98: • int& & is collapsed to int&. • In C++11, the rules are: (in addition to the above) • int&& & is collapsed to int&. • int& && is collapsed to int&. • int&& && is collapsed to int&&. • Therefore, only the T&& version should be enough. • If you pass in an lvalue to our move, the actual argument type will collapse into T&, which is what we want (probably!) http://yaserzt.com/
std::move (3/5) • So, move looks like this thus far:template <typename T>??? move (T && something){returnsomething;} • Now, what is the return type? • T&& ? • It should be T&& in the end. • But if we declare it so, and move() is called on an lvalue, • then T will be SomeType& • then T&& will be SomeType& && • then it will collapse into SomeType& • then we will be returning an lvalue reference from move(), which will prevent any moving at all. • We need a way to remove the & if T has one. http://yaserzt.com/
std::move (4/5) • We need a mechanism to map one type to another • In this case, to map T& and T&& to T, and T to T. • There is no simple way to describe the process, but this is how it’s done: • template<typename T> structRemoveReference{typedefT type;}; • With that, RemoveReference<int>::type will be equivalent to int. But we are not done. • Now we specialize:template<typenameT> structRemoveReference<T &>{typedefTtype;};template<typenameT> structRemoveReference<T &&>{typedefTtype;}; • Now, RemoveReference<int&>::type will be int too. http://yaserzt.com/
std::move (5/5) • Our move now has the correct signature:template<typenameT>typenameRemoveReference<T>::type && move (T && something){returnsomething;} • But it’s not correct. That “something” in there in an lvalue, remember? • So we cast it to an rvalue reference:template <typenameT>typenameRemoveReference<T>::type && move (T && something){returnstatic_cast<typenameRemoveReference<T>::type &&> (something);} • Hopefully, this is correct now! http://yaserzt.com/
Variadic Templates • Templates with variable number of arguments • template <typenameT, typename... PTs>T* Create (PTs&&... ps){T* ret = newT; ret->create (ps...);returnret;} • Rules of expansion very interesting… • PTs… and ps… are not types, nor values, arrays, tuples, initializer lists. There are new “things”. http://yaserzt.com/
Using async and future #include<future> string flip (strings) { reverse (s.begin(), s.end()); returns; } int main () { vector<future<string>> v; v.push_back(async ([] {return flip( " ,olleH");})); v.push_back(async ([] {return flip(" weNevarB");})); v.push_back(async ([] {return flip( "!dlroW");})); for(auto& i : v) cout<< i.get(); cout<< endl; return0; } http://yaserzt.com/
Other Assorted Features • Initializer lists • static_assert(expr, "message"); • Delegating constructors • Member initialization in class declaration • Explicitly overriding inherited methods • Explicitly using or not using default methods • UTF8, UTF16, UTF32 and raw string literals • User-defined literals • Libraries for regular expressions, shared pointers, threads, working with the file system, tuples, atomic operations,… (mostly from TR1 and Boost.) http://yaserzt.com/
References (i.e. Source Material) • Wikipedia article on C++11 at http://en.wikipedia.org/wiki/C%2B%2B11 • Scott Meyers, Herb Sutter and Andrei Alexandrescu – C++ and Beyond (lectures and presentations) • Presentations by BjarneStroustrup and Stephan T. Lavavej from Going Native 2012 • Microsoft’s implementation of the C++11 Standard Library (accompanying VC11 Beta) • C++11 published standard: ISO/IEC 14882:2011 • A draft (very similar to the published standard) is available at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf http://yaserzt.com/
Contact us at http://fanafzar.com/ If you have a shotgun, you don’t have to use it to kill mosquitoes. But it’s a lot of fun! Any questions?
Zero-cost Abstractions • Hardware is the platform – everything else is just croft • Abstractions are necessary (d’oh!) • Good abstractions let you express more • Good abstractions let you declare intent • Good abstractions can increase performance • memcpy() vs. std::copy() • qsort()vs. std::sort() http://yaserzt.com/
Threads (1/2) classthread { public: classid; thread (); template<classF, class... Args> explicitthread (F&& f, Args&&... args); ~thread(); booljoinable() const; voidjoin(); voiddetach(); idget_id() const; staticunsignedinthardware_concurrency(); }; http://yaserzt.com/
Threads (2/2) namespacethis_thread { thread::idget_id(); voidyield (); voidsleep_until (abs_time); voidsleep_for (rel_time); } http://yaserzt.com/