1 / 44

Brown Bag #2

Brown Bag #2. Advanced C++. Topics. Templates Standard Template Library (STL) Pointers and Smart Pointers Exceptions Lambda Expressions Tips and Tricks!. Templates. Generic code that works with many data types Encourages code reuse Turing-complete

vahe
Download Presentation

Brown Bag #2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Brown Bag #2 Advanced C++

  2. Topics • Templates • Standard Template Library (STL) • Pointers and Smart Pointers • Exceptions • Lambda Expressions • Tips and Tricks!

  3. Templates • Generic code that works with many data types • Encourages code reuse • Turing-complete • Template metaprogramming (not covered) • Beware scary compiler/linker errors

  4. Function Templates int Square(intnum) { returnnum * num; } • A family of functions • Uses a generic type • On demand compilation • Compiler can deduce types • Type-safe template<typenameT> T Square(Tnum) { returnnum * num; } float result = Square(5.0f); int result = Square(2);

  5. Class Templates template<classT> classThing { public: Thing(T data) : m_data(data) {} TGetData() const { returnm_data; } private: T m_data; }; • class and typename are interchangeable • Explicit type specification • Declaration + implementation in same file • Can template methods not just whole classes • Great for containers Thing<int> myThing = Thing<int>(50); int data = myThing.GetData();

  6. Standard Template Library (STL) • Containers • vector • list • map • string • Algorithms • for_each • find • sort • Iterators • auto keyword (not directly relevant, but handy)

  7. vector • Dynamic array • Access item at index = constant time • Iterate over all elements = linear time std::vector<Thing> myVector; myVector[0].foo(); std::vector<Thing>::iterator for ( autoiter = myVector.begin(); iter!= myVector.end(); ++iter) { iter->foo(); }

  8. for_each #include <algorithm> #include <vector> usingnamespacestd; • voidmyFunction (inti) { cout << " " << i; } • intmain() • { • vector<int> myVector; • myVector.push_back(10); • myVector.push_back(20); • for_each (myVector.begin(), myVector.end(), myFunction); • }

  9. string • Special container type – sequence of characters. • Contains useful functions and common STL container functionality. #include <string> • int main() { std::string test(“Hello World!”); std::cout << “Length of string is “ << test.size() << “.\n”; // 12 }

  10. map • Associative container that stores values as a <key, value> pair. • An array uses an integer as the key type. • Each element must have a unique key. • Map containers support iterators that return key and value. #include <map> • using namespace std; • int main() { map<string, int> testMap; testMap.insert(map<string, int>::value_type(“Hello”, 5); intmyInt = testMap[“Hello”]; cout << “Value contained in element with key ‘Hello’ is “ << myInt << “.\n”; // 5 }

  11. Pointers • Pointers are references to memory blocks which contain data (or an instruction). • We access this data using the reference (&) and dereference (*) operators.

  12. Dereference Operator (*) • If a pointer is a memory address, how do we access the object at that location? • Dereference a pointer to obtain the value at the memory address.

  13. Reference Operator (&) • How do we alter a value at a given memory address and not just a copy? • Use the Reference operator to obtain a variable's memory address.

  14. Pointer to a Pointer • It is possible to have a pointer that points to another pointer.

  15. Pointer to a Pointer • Ever seen a DirectX function where you pass in a reference to a pointer? Check the argument list - that's what is happening there!

  16. Class and Struct Pointers • You can create pointers to struct and class objects using the 'new' keyword: • Lets try setting the value of ack::bar to 5:

  17. Class and Struct Pointers • This is C# syntax - doesn't work in C++!

  18. The -> Operator • Like before, we must dereference the pointer before we can access the object! • There's a nicer way: • The -> operator dereferences a class or struct pointer and gives access to its members. • This is known as "syntactic sugar".

  19. ‘delete’ and Null Pointers • When you de-allocate a pointer using the 'delete' keyword, it is common to set the pointer's value to 0: • A pointer whose value is 0 is known as a null pointer.

  20. Smart Pointers • These can be found in the Standard Library as part of the <memory> header file. • There are three types: • unique_ptr • shared_ptr • weak_ptr

  21. Smart Pointer Syntax • Pointers declared using template-style syntax: • * and & operators can be utilised as normal: • Memory is de-allocated at the end: • However, de-allocation does not need to be done manually!

  22. Reference Counting • Smart pointers count the number of references to an object in memory. • When a pointer leaves scope, the reference count is decremented. • When the reference count reaches 0, the memory is de-allocated.

  23. unique_ptr • Allows for only one reference to a stored object - it is unique. • This is an invalid operation. However, ownership can be transferred: • When memory is de-allocated:

  24. shared_ptr • shared_ptrs allow for multiple pointers to reference the same memory address.

  25. weak_ptr • To avoid circular references, we use weak_ptrs: • In order to access the shared_ptr, we use weak_ptr::lock(): • When the shared_ptr is deallocated, weak_ptr::lock() will return an empty shared_ptr object:

  26. nullptr • Traditionally, a null pointer is defined as NULL, or 0. Consider the following: • How do we distinguish between 0 and a null pointer? • C++11 introduces the nullptr type: • Now we no longer need to worry about confusing null pointers and int values!

  27. Smart Pointers: Summary • Smart pointers allow for all the same functionality of a standard pointer. • Makes use of Reference Counting for automatic de-allocation. • unique_ptr makes it easier to store single references to objects at a time. • shared_ptr allows for multiple pointers to share memory. • weak_ptr allows for accessing shared_ptr objects with easy clean-up. • nullptr helps to clearly distinguish from numeric values.

  28. Simples!

  29. Exceptions try { throw 20; } catch (int e) { cout << “Exception:" << e << endl; } • Handle exceptional runtime errors • Unwinds stack (releases local variables, etc.) • Used by standard library / STL • Standard exceptions (bad_alloc, bad_cast, etc.) • Custom exceptions (extend std::exception) • Exception specifications floatfoo(charparam) throw (int);

  30. Exceptions: The Good • Cleaner than error codes • Much nicer for deeply-nested functions • Separates error-handling from program flow • User-definable to carry detailed information • Catch constructor errors

  31. Resource Acquisition Is Initialization (RAII) • Only destructors are guaranteed to run after an exception is hit • Use destructors to prevent resources leaks • Doesn’t require messy try/catch blocks • voidfoo(void){std::unique_ptr<Thing>myThing(new Thing() );myThing->Something();}

  32. Exceptions: The Bad, The Ugly • Multiple program exit points • Changes program flow, maybe harder to debug • Make debugger break on exceptions in Debug • Potential to leak resources if misused • Use smart pointers, etc. to avoid • Exception-safe code can be hard to write • Don’t throw in destructors • Only throw on exceptionalerrors • Hard to introduce to existing code

  33. Lambda Expressions [ ] () mutable throw() –> int { } • Related to the concept of anonymous functions. • Helps to solve the problems of function objects and function pointers. • Function pointer has minimal syntactic overhead but does not retain state. • Function object retains state but requires the overhead of a class definition. • Lambdas feature minimal overhead and can retain state within the scope in which they are defined.

  34. Lambda Expressions: Example • voidLambdaExample() { automyLambda = [](int x, int y) -> int { return (x * 2) + y; }; int a = 3; intb = 4; intc = myLambda(a, b); std::cout << “The value of c is “ << c << “.\n”; // 10 int d = myLambda(c, b); std::cout << “The value of d is “ << d << “.\n”; // 24 }

  35. Lambda Expressions: Syntax • Capture Clause: [ ] • Used to access variables from the scope enclosing the lambda. • Can be passed by reference or value (e.g. &x, y). • Default capture mode can be specified using & or = at the beginning for reference or value captures respectively (e.g. [&, x] or [=, y]). • ‘this’ pointer provides access to member variables of the enclosing class (e.g. [this]). • Parameter List: () • Specifies the parameters passed into the function, as with a regular function declaration. • Mutable Specification: mutable • Allows values captured by reference to be modified within the function. • Will not change the original value, only the local copy.

  36. Lambda Expressions: Syntax (cont.) • Throw Specification: throw() • Specifies if the lambda can throw an exception. • throw() specifies no exception can be thrown. • throw(T) specifies an exception of type T can be thrown. • Return Type: -> T • Follows trailing return-type syntax introduced in C++11. • Explicitly specifies the return value of the function. • Can be implicitly implied via a return statement in the function body. • Function Body: { } • Defines the instructions to be performed, as with a standard function.

  37. Lambda Expressions: Example Revisited • voidLambdaExample() { automyLambda = [](int x, int y) -> int { return (x * 2) + y; }; int a = 3; intb = 4; intc = myLambda(a, b); std::cout << “The value of c is “ << c << “.\n”; // 10 int d = myLambda(c, b); std::cout << “The value of d is “ << d << “.\n”; // 24 }

  38. Why use Lambda Expressions? • #include <vector> • #include <algorithm> • intmain() • { • std::vector<int> myVector; • myVector.push_back(10); • myVector.push_back(20); • inttotalCount = 0; • for_each (myVector.begin(), myVector.end(), [&totalCount](int x) • { • totalCount += x; • }); • std::cout << “The total of all values in myVector is “ << totalCount << • “.\n”; // 30 • } • Iterator functions:

  39. Why use Lambda Expressions? • #include <ppltasks.h> • usingnamespace Concurrency; • intmain() • { • autodoubleNum = [](int x) { return x * 2; }; • autoincrementNum = [](int x) { return ++x; }; • autostartTask = create_task([]() -> int { return 5; }); • intfinalNum = • startTask.then(doubleNum).then(incrementNum).then(doubleNum).get(); • std::cout << “The value of finalNum is “ << finalNum << “.\n”; // 22 • } • Asynchronous tasks:

  40. Tips and Tricks

  41. Const FTW • Prefer pass-by-reference-to-const to pass-by-value (item #20) • Avoid unnecessary constructors/destructor calls • Still guarantee to caller that object won’t be changed voidFoo( constThing& input ); • const member functions (getters) ThingGetData() const;

  42. Enums FTW • Nicer and safer than pre-processor definitions • Enum classes/structs (C++ 11) • Old: Wrap Enums in struct • Now type-safe in C++ 11 structMyEnum { enumEnum { MAX }; }; enumclassMyEnum { MAX };

  43. Further Reading • Microsoft Developers Network (MSDN) • CPlusPlus.com

More Related