Skip to content

banach-space/cpp-tutor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cpp-tutor

Apple Silicon x86-Ubuntu

Code examples for tutoring modern C++.

tl;dr

Study by reading the source files, building the executable and running them to see the output.

Summary

The intent of this tutorial is to give a quick overview of some of the most important and interesting features of C++, and to do so in a form of complete and self-contained examples. It focuses on modern C++ (C++11/C++14/C++17), but there are also some pre C++11 and C-specific examples for comparison. It's by no means complete - quite the contrary. It aim is to be:

  • Concise: the examples are short, yet complete - to the point. There's a source file implementing the main function for each items and you can study it in complete isolation from other items.
  • Selective: the examples emphasise features and corner cases most likely encountered when just starting with modern C++. They focus on key points rather then presenting the complete picture. Less is more.
  • Clear: the examples sacrifice code quality in favour of code clarity and readability, e.g. in some cases there's more comments than code. Also, see the disclaimer

It is assumed that you already know some basic C++ and are familiar with object-oriented programming. These code samples will be helpful if you're switching to C++ from a different object oriented language, are preparing for an interview, or, like myself, are mentoring junior C++ developers.

Disclaimer

The examples presented here are meant to highlight (and sometimes exploit) the specifics and quirks of the language. To this end, the presented examples may exhibit undefined or implementation specific behaviour, or implement solutions that are against good coding practices. This is done for educational purposes only and always thoroughly documented.

This repository is self-published and has not been peer-reviewed in the traditional sense.

Status

WORK-IN-PROGRESS

Platform Support

The only requirement for cpp-tutor is a C++17 compliant compiler and CMake-3.4.3 or newer. It is supported on Linux, Mac OS X and Windows, and is regularly tested against the following configurations (extracted from the CI files: .travis.yml and appveyor.yml):

  • Linux Ubuntu 16.04 (GCC-7 and LLVM-7)
  • Windows (Visual Studio 2015)
  • Mac OS X 10.13 (Apple LLVM 10)

Please refer to the CI logs (links at the top of the page) for reference setups.

Usage

The items covered in this tutorial are independent and you can be studied in any order that works for you. Once you choose an item that's of interest to you, go through the links and code samples available below. Next, build and run it. Most executables print to stdout. Make sure that you understand where the output comes from, what it means and that it matches the comments in the code.

Some examples implement undefined behaviour, contain compiler errors or code that leads to memory leaks. Such broken or problematic parts of the code are guarded off with preprocessor symbolic constants:

  • COMPILATION_ERROR
  • MEMORY_LEAK
  • DANGLING_REF_OR_PTR
  • RUNTIME_ERROR

Be default all symbolic constants are undefined and hence there are neither compilation errors nor memory leaks. Play around by defining them (one at a time), recompiling and re-running the examples. Make sure that the generated output (or compiler errors) makes sense. Comments in the corresponding source files might be instrumental in understanding those.

Remember to re-build and re-run the examples before and after defining MEMORY_LEAK/DANGLING_REF_OR_PTR/RUNTIME_ERROR (defining COMPILATION_ERROR will prevent the code from compiling, so it's not really relevant here).

Memory leaks

If you're developing on Linux, you can use Valgrind to get a better grasp of memory leaks implemented in some of the examples, e.g.:

$ cd <build_dir>
$ valgrind smart_pointers

(<build_dir> is the build directory used when building the project).

On other platforms, you can use AddressSanitizer. This has already been integrated for you, but currently only for clang and gcc. In order to use the address sanitizer, set the build type to ASAN, and run your example like this:

$ ASAN_OPTIONS=detect_leaks=1 strings_pool

Runtime errors

The special case of runtime errors requires additional explanation. In most cases the code guarded with RUNTIME_ERRORS exhibits undefined behaviour, and as a result anything can happen. Although often the actual behaviour can be predicted with a good amount of accuracy (because compilers, runtimes and operating systems are relatively stable), do bare in mind that the output will depend on the system that you use.

Build Instructions

It is assumed that cpp-tutor will be built in <build-dir> and that the top-level source directory is <source-dir>. For brevity, the build instructions are presented for Linux only.

First, you will need to clone Google Test inside <source-dir>:

$ cd <source_dir>
$ git clone https://github.com/google/googletest.git

Next, you can build all the examples as follows:

$ cd <build-dir>
$ cmake <source_dir>
$ make

This will generate all the targets implemented for this project. If you want to (re-)build a particular example, run:

$ make <example_name>

Build types

Set the CMAKE_BUILD_TYPE variable to:

  • Release to generate optimised code
  • ASAN to generate build unoptimised code, with plenty of good debug info and configured to be run with address sanitzer

Switching between C++ standards

The default C++ standard for the whole project is set to C++17. In order to rebuild using C++11 or C++17, use CMAKE_CXX_STANDARD. For example, to build in C++17 mode:

$ cd <build-dir>
$ cmake -DCMAKE_CXX_STANDARD=17 <source_dir>
$ make

This will be very helpful when looking at how certain constructs have evolved with the language.

Disabled code

As explained elsewhere in this README.md, some of the examples contain code disabled with preprocessor symbols. In order to enable one of such blocks, define the corresponding preprocessor symbol by re-running CMake like this:

$ cmake -D<PREPROCESSOR_SYMBOL>=1 .

in which PREPROCESSOR_SYMBOL is one of:

  • COMPILATION_ERROR
  • MEMORY_LEAK
  • DANGLING_REF_OR_PTR
  • RUNTIME_ERROR

This will update <build_dir>/include/cppt_ag.hpp, the CMake auto-generated header file that will be updated with the required definition. Next, re-build and re-run your example.

Items

The items covered in this tutorial so far (with some relevant links):

  1. Strings (even more strings)
    • C-strings vs std::string vs std::string_view
    • the underlying data-representation
    • SSO (Short String Optimisation)
    • std::string vs std::string_view (performance comparison)
    • source files:
      • strings_1_main.cpp and strings_reverse.cpp
      • strings_2_main.cpp
      • strings_3_main.cpp
  2. Dynamic memory allocation
    • all forms of new and delete (for plain datatypes and classes)
    • dynamic array of dynamic objects (a.k.a. 2-dimensional dynamical arrays)
    • memory leaks caused by mismatch in new and delete
    • deep vs shallow copy
    • a basic memory manager implemented in terms of placement new
    • source files:
      • pointers_main.cpp
      • deep_vs_shallow.{hpp|cpp}, deep_vs_shallow_main.cpp
      • strings_pool_main.cpp, strings_pool.{cpp|hpp}, tests_strings_pool.cpp,
  3. C++ Unit testing
    • GTest and test fixtures
    • embedding GTest tests into the build system
    • source files:
      • cpp_tutor_ut_main.cpp, CMakeLists.txt, tests_strings_object.cpp, tests_strings.cpp
  4. Smart pointers
    • std::unique_ptr, std::shared_ptr, std::weak_ptr
    • std::make_unqiue and std::make_shared
    • source files:
      • smart_pointers_main.cpp
  5. L-value and R-value
    • l-value vs r-value
    • l-value reference vs l-value to const reference vs r-value reference
    • std::move vs std::forward
    • source files:
      • rvalue_vs_lvalue_main.cpp
  6. Move semantics
    • move constructor and move assign operator
    • source files
      • memory_block.cpp, memory_block_main.cpp
  7. Return Value Optimisation
    • (N)RVO
    • guaranteed copy elision (C++17)
    • source files:
      • rvo_main.cpp
  8. New kewords in C++11 and beyond
    • const vs constexpr, nullptr, auto, decltype
    • source files:
      • const_vs_constexpr_main.cpp, null_vs_nullptr_main.cpp, auto_vs_decltype_main.cpp
  9. Explicit type conversion (a.k.a. casting):
    • explicit vs implicit type conversion
    • C vs C++ style casts (static_cast, dynamic_cast, reinterpret_cast, const_cast)
    • source files:
      • type_casting_main.cpp
  10. Initialization in modern C++ (is bonkers)
    • init values for variables with automatic and static storage duration
    • types of initialization (direct, copy, value, list)
    • brace elistion in list initialization
    • initializing aggregate types
    • various gotchas when using initilizer lists
    • source files:
      • init_stack_vs_global_vars_main.cpp, init_aggregate_main.cpp, init_brace_elision_main.cpp, init_types_of_main.cpp, init_list_gotchas_main.cpp

License

The MIT License (MIT)

Copyright (c) 2018-2019 Andrzej Warzyński

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Releases

No releases published

Packages

No packages published