C _basics - RicoJia/notes GitHub Wiki

  1. sizeof: returns the number of bytes,

    • works with array, but not ptr.
      int arr[]={1,2,3,4,5};
      int* arr_ptr = arr; 
      cout<<sizeof(arr)<<endl;		//works
      cout<<sizeof(arr_ptr)<<endl;	//doesn't work
  2. =:doesn't have a defined order of evaluation!

    individual_camera_feeders_[params->rtsp_url_] = std::make_unique<IndividualCameraFeeder>(std::move(params), bag_mode_);     //params may be moved before params -> rtsp_url_!
  3. I made an "enum" for C++17, built on top of range-based loop

    for (auto i : iterable){} 
    // Is equivalent to 
    for (It it  = iterable.begin(); it != iterable.end(); it++){
        auto i = * it; 
    }
    • So we wrap this iterable, with an iterator that shows the index
      // requires T to have default ctor
      // SFINAE with typename
      #include <tuple>
      template <typename T,
                typename TIter = decltype(std::begin(std::declval<T>())),
                typename = decltype(std::end(std::declval<T>()))
                >
      constexpr auto enumerate(T&& iterable){
          struct iterator{
              size_t i;
              TIter iter;
              bool operator != (const iterator& other){return other.iter != iter; }
              void operator ++(){
                  ++i; ++iter;
              }
      
              auto operator *(){
                  return std::tie(i, *iter);
              }
          };
      
          struct iterable_wrapper{
              T iterable;
              auto begin(){return iterator{0, iterable.begin()}; }
              auto end(){return iterator{0, iterable.end()}; }
      
          };
      
          return iterable_wrapper{std::forward<T>(iterable)};
      }
      
      
      //usage: 
      for (const auto&[index, item]: enumerate(vec)){
          ...
      }
  4. subscription operator []

  • if we use [],we assume the object has a valid name, and a valid memory address, and that means we are working with lvalues
  • So for lvalues, returning a reference allows you to: 1. modify the value 2. more efficient
  class Array{
      ...
      int& operator [] (unsigned int i){return arr[i];}  
    }

Assert

  1. assert
      #include <cassert>
      assert(0);

Using

  • Uses
    • replace typedef
      typedef std::unique_ptr<int> p; 
      using p = std::unique_ptr<int>; 
    • [REVIEW] Template Alias: short hand for a templated struct or class
      template <typename T>
      struct MyList{
          std::list<T> list_; 
        };      //It's just a std::list with a templated param. 
      
      //Use: 
      template <typename T>
      using MyList = std::list<T>; 
      
      MyList<int> ls;

========================================================================

iostream

========================================================================

  • Basics
    • Structure
     ostream -> ofstream
     					-> fstream (so fstream can access both)
     istream -> ifstream 
    
      - Note: so if you have #include <fstream>, you can get both ifstream and ofstream. 
    
    • You can only write to any output stream, and read from any input stream.
  • cout
    • is thread-safe.
    • is a stack (LIFO).
  • General Cautions
    • Do NOT copy streams, because a stream might contain bits that have & haven't been read, copying a stream doesn't make much sense. The copy constructor of stream has been disabled.

ofstream - output file stream

  1. automatically destructs when goes out of scope (exception safe)
    //write to file
    ofstream
    write.open("test3.txt)
    write << "Scores " << 85 << " " << 73 << " " << 99 << endl;
    write.close();
  2. std::setw: set output stream width
    #include <iostream>
    #include <iomanip>
    std::cout <<"setw(6): [" << std::setw(6) << 42 << "]\n"   // see setw(6): [    42]
  3. std::setfill, sets the default char to something
    #include <iostream>
    #include <iomanip>
    int main()
    {
        std::cout << "default fill: [" << std::setw(10) << 42 << "]\n"    // see default fill: [        42]
                  << "setfill('*'): [" << std::setfill('*')               // setfill('*'): [********42]
                                       << std::setw(10) << 42 << "]\n";
    }
  4. print stuff in hex using std::hex
    std::cout << "The number 42 in octal:   " << std::oct << 42 << '\n'
              << "The number 42 in decimal: " << std::dec << 42 << '\n'
              << "The number 42 in hex:     " << std::hex << 42 << '\n';

ifstream

  1. Basic Example

    #include <iostream>
    #include <fstream>
    #include <string>
    using std::cout; using std::endl; 
    std::ifstream read("hehe.txt");
    std::string line;
    if (read.is_open()){
        while(getline(read, line)){
            cout<<line<<endl;
        }
        read.close();
    }
  2. read chars into vector

  • istream_iterator is an input iterator, its ++ uses operator >>
  • it has an end of stream iterator, which is constructed out of nothing.
    #include <iostream>
    #include <iterator>
    #include <fstream>
    #include <vector>
    std::ifstream is("numbers.txt");
    std::istream_iterator<double> start(is), end;
    std::vector<double> numbers(start, end);
  1. fopen(file_name, "wb") will erase the old content, then appending new content onto it.

other streams

  1. cout<<uint8_t will print a char!
  2. std::ifstream is also not copyable but movable

========================================================================

Enum

========================================================================

  • Basics

    • enum color {black, white} is callled "unscoped enum (C++98)"
    • scoped enum's Default type is int, unscoped enum doesn't have a default underlying type. But you can specify them for both cases.
  • Unscoped Enum vs scoped enum [REVIEW]

    • Caution: unscoped enum leaks names, while scoped enum doesn't pollute namespace

      enum Color{red, black}; 
      auto red = false;   //red has been defined in enum, you can't use it
      Color c = red;      //this is legal, but will polute namespace
      
      enum class Color_2{white}; 
      auto white = false;   //this doesn't leak names.
      Color C = white;    //Not good!!
      Color C = Color::white;   //this is findSmaller
      auto C = Color::white;    //also fine
    • Caution: unscoped enum may convert to double implicitly, while scoped enum doesn't have such a problem

      • So you must use static_cast to explicitly convert it.
        enum Color{
            black, red
          }; 
        Color c = red; 
        if (red < 14.5);    //THIS IS LEGAL, so it's bad 
        
        Color_2 d = Color_2::red; 
        if (d < 14.5);    // illegal
        if (static_cast<double> d < 14.5)
    • Caution: unscoped enum requires extra work to be forward-declared, scoped enum doesn't

      • unscoped enum doesn't have a default underlying type, for scoped type, the default is always int.
      • So compiler needs to determine unscoped enum's size
        • Usually compiler will find smallest type such as char, but it might trade size for time.
      • So if you want to forward declare unscoped enum, you must specify size
      • You can also specify size on scoped enum for forward declaration
        enum Color{
            red = 0
            black =  0xFFFFFFFF
          };    //This may happen
        
        enum class Color_2 {red, black}; 
        
        // In another file
        enum Color: std::uint32_t;  //this is valid
        enum Color_2;     // This is valid
        
        enum Color_2: std::uint32_t;    //this is also valid
    • Advantage of unscoped enum: design pattern for looking up a field in tuple, using its implicitly conversion [REVIEW]

      using UserInfo = std::tuple<std::string, std::string, std::size_t>; 
      enum Fields{uiname, uiEmail, uiReputation};   //store the field number 1,2,3 as uiname ... 
      
      UserInfo info; 
      auto val = std::get<1>(info); // I can't remember what field 1 was ... 
      auto val = std::get<uiname>(info); 
      • Using scoped enum will be much more verbose:
        enum class Fields{uiname, uiEmail, uiReputation};   //store the field number 1,2,3 as uiname ... 
        auto val = std::get<static_cast<std::size_t>(Fields::uiname)>(info); 
    • frequently-changed enum can have a reference

      enum Foo{
        Field_One = 1; 
        Field_Two = 2; 
        __First__ = Field_One;      // in the future you may have a different field
      }; 
      
      vec.at(__First__) is a good practice
    • enum class is strongly typed. So even though the underlying type is unsigned int, it still cannot be converted to unsigned int directly. So use unscoped enum if you wish

      enum class Foo : char{
        STUFF
      }
      char i = Foo::STUFF;    //wrong. use static_cast
      • unscoped enum
        enum Foo{
            STUFF; 
        };
        int i = STUFF;    //fine 
        int i = Foo::STUFF;   // fine

========================================================================

iomanip

========================================================================

#include <iostream>
#include <iomanip>
#include <ctime>
 
int main()
{
    std::time_t t = std::time(nullptr);
    std::tm tm = *std::localtime(&t);
    std::cout << "ru_RU: " << std::put_time(&tm, "%c %Z") << '\n';
}
  • POD (plain old data, i.e, no ctor or dtors)

========================================================================

Include

========================================================================

  1. order of inclusion in hpp: if A.hpp should include B.hpp but doesn't, then this in c.cpp may "cover" this problem, which is not good:
    #include "B.hpp"
    #include "A.hpp"

========================================================================

Functions

========================================================================

Passing a Function

  1. Passing function as argument and having default argument:func( double another_func = func2)
  • should only be defined once in class declaration or definition, but not at the same time!!

Inline Functions

  1. 一个完整的function call 会callee give the function control -> cpu find the instruction addresses, puts them on stack -> execute function instructions -> return the values to predesignated memory-> return control to the callee function.

  2. 当你return control to the callee function 相对耗时很长时(你实际function很短),你可以减少这个control 所谓switching time (overhead),因为这些短的程序可能会被经常调用。所以你可以搞inline func(){}... 这个inline是一个request(不是一个command) 给compiler,让compiler把整个程序copy到callee里边。

  3. Inline function - 【one definition rule】所以你要在h file 中把整个的declaration 都要写出来,不然有可能会有overloading【???】

  4. Header File: 每个std中的类型都有一个header file。如std::string,所以你要 #include

  5. In a class,

    • functions defined inside the class is implicitly inline. So this is bad:
    class Foo{
        public: 
            inline int lol(){return 1; }    //inline is redundant here
    }

    This is good:

    class Foo{
        public: 
            int lol(); 
    }
    inline int Foo::lol(){return 1; }   //this is good. 
    • Virtual functions cannnot be inline, since they're resolved during run time.
      • override is an identifier that enforces cpp to check for a virtual base class. If there's not one, there will be an error.

Control-Flow

  • switch case? [REVIEW]
    • break is optional. If omitted, control will go on until reaching the next break.
    • default is optional too.
      switch(var)
        case 1: break; 
        default: 
  • try-catch
    • you can have multiple catch statements:
      try {
        // code here
      }
      catch (int param) { cout << "int exception"; }
      catch (char param) { cout << "char exception"; }

========================================================================

Keywords

========================================================================

Storage Specifiers

  1. C keywords

    • static
    • auto (automatic, in functions, etc.)
    • register
  2. thread_local

    • global/static variable but actually has a copy in each thread

    • example

      thread_local int i;     //global thread_local
      class Foo{
        static thread_local int j;    //thread_local class members
      };
      static thread_local int Foo::j; 
      void foo(){
        thread_local int k;     //thread_local class variables
      }
      1. k is automatically a "static" variable during the life of a thread.
        • k will be initialized the first time foo() is called.
      2. i and j will be initialized before they're first used, but we don't know when exactly - if we don't use them, they may not be constructed at all (compiler dependent).
      3. i, j, k are zero initialized, like static variables.
      4. if i,j,k throws errors during construction, std:;terminate will be thrown.
    • Useful in random number generator.

      1. you need a seed for each thread. It can appear static/global, but actually each thread has a copy
      2. If you use a true global variable, other threads can interfere.
      3. local variable will get initialized everytime, so you get the same number.
      4. Only variable name matters
    • When you pass in a pointer, it's just a normal pointer

      thread_local int i=0;
      void thread_func(int*p){
          *p=42;
      }
      
      int main(){
          i=9;
          std::thread t(thread_func,&i);
          t.join();
          std::cout<<i<<std::endl;    // now you get 42
      }
  3. Static Global Variable

    • static global variable in cpp file, has scope limited to the current cpp file. So header including extern accidentally will not complain about multiple-definitions.
      // header.hpp"
      extern int i;
      // src1.cpp
      #include "header.hpp"
      static int i = 3;   // no multiple definition
      //src2.cpp
      #include "header.hpp"
      int i = 4; 
    • Golden Rule: static keyword is only used with the declation, never in the definition.
      class Foo{
          static void bar(); 
      };
      static void Foo::bar(){}  //error: cannot allow to have static linkage, remove static

explicit

  • 但是你要有explicit,即explicit foo(int n,int m=20):num(n),num2(m){},那么这种type conversion 就被禁止了,你只能有foo bar(3) 而不是foo bar = 3;
    • When a ctor has only one argument, then it becomes a conversion ctor
      • So this ctor can either implicitly or explicitly cast the single argument to an object
    • Explicit will ban (and only) ban that implict conversion
      class Foo{
          explicit Foo(double r = 0.0, double i = 1.0); 
          bool operator== (Foo rhs); 
        }
      int main(){
          Foo f1(3.0); 
          if (com1 == 3.0)      //Without explicit, this is legal: 3.0 will be IMPLICITLY converted to a temp Foo object. 
            // Now with explicit, this is banned. 
            ...
      
          if (com1 == (Foo)3.0)       // This is still legal, cuz explicit will ONLY ban implicit conversion. 
        }
    • explicit 只能用在class definition 里面。
    • explicit: 只有constructor, conversion operators need this

=delete

  • Motivation (C++11)

    • We want to prohibit using some functions.
  • Basics

    • delete works on ANY FUNCTION
    • in C++98, there's an equivalent - declaring a class and delibrately having it undefined
      • but that doensn't work outside classes, and not fully inside class.
  • Uses & Comparison with C++98 equivalent

    1. Use in a class - the only functions we don't want is the automatically generated ones. Say we don't want users to use copy constructors
      class Foo{
        public: 
          Foo& (const Foo&) = delete;   //C++11 way, the better way
        private: 
         Foo& (const Foo&);     // C++98 way, so either no access to this function, or child/friend classes will get an error.  
      }
    • As a convention, delete functions in a class is always place d in public
      • That's because on some compilers, they might complain about the function being private. So here you have a better error msg.
    • In C++98, class is the only place that you see a declaring undeclared private function, no other places, while =delete can be used anywhere, on any function
    • In C++98, if there's an error, you'll only see that during link-time.
    1. Non-member functions - C++98 cannot deal with this
    bool isLuckyNumber(int number){...}   // This is what we want
    bool isLuckyNumber(char number) = delete   // Not what we want
    bool isLuckyNumber(double number) = delete   // Not what we want
    - Caution: float will be banned here too as a side effect, because **float will always implicitly convert to double**
    ```cpp
      float i = 3.5; 
      isLuckyNumber(i);     // Not work!
    ```
    
    1. Templated Functions
      template <typename T>
      void processPointer(T* ptr){
        ...
      }
    
      //Now we want to ban void*, char*, because 1. you can't increment void*, 2. char* is always a pointer to a c_str. 
      template <>
      void processPointer(char* ptr) = delete; 
    
      template <>
      void processPointer(void* ptr) = delete; 
    
      template <>
      void processPointer(const char* ptr) = delete;
    
      template <>
      void processPointer(const void* ptr) = delete;
    - In a class, you **CAN'T** do it in C++98 way, because template specialization cannot be private. 
      ```cpp
      class Foo{
          public: 
            template <typename T>
            void processPointer(T* ptr){
              ...
            }
            template <>
            void processPointer(const void* ptr) = delete;   //C++11, Works!
          private:
            template <>
            void processPointer(const void* ptr);   //C++98, error
    
              }
            ```
    

Null ptr and null pointer

  • NULL vs nullptr
    • NULL is a just macro of integral type, with values 0 or 0L (long int). These values are also called "null pointer constants". In C, Null could also be (void*) 0;
       void castSpell(int spellID);
       castSpell(NULL); 	//this works!
      
    • Other dangers of NULL or 0:
      • other programmers don't know if this is pointer type
      • Yeah NULL or 0 works with smart pointers individually, but templates can only deduce them as int type. Which causes a problem
         template<typename FuncType, typename PtrType>
         decltype(auto) lockAndCall(FuncType func, // C++14
          PtrType ptr)
         {
          return func(ptr);
         }
        
         void func(std::unique_ptr<int> ptr_1){}
        
         int main()
         {
         	lockAndCall(func, NULL);		//this causes problem
         	 return 0;
         }
         
    • nullptr is
      • a const expression evaluated at value 0, of type std::nullptr_t
      • convertible to pointer types, but it's not an integral type.
      • Always use nullptr instead of NULL!

noexcept (Need further work)

  • Motivation:

    • a function specifier to tell the compiler: it's okay to generate some optimized code for this function.
    • So stack-unwinding is ommited for functions declared noexcept.
  • Basics

    • noexcept is just a compile time specifier, so code will be optimized.
    • Or noexcept(Some_func); can be used to tell if a function has noexcept
      • potentially throwing vs non-throwing code:
        • potentially throwing:
          • regular funcs,
          • user-defined constructors
          • operators such as new
        • Non-throwing: if a user defined one uses a potentially throwing func, it will become potentially-throwing
          • default ctor
          • The big five (copy ctor, -, move ctor, =, dtor)
      • e.g
        noexcept(5+3);    //return true, int are non-throwing
        noexcept(some_struct{})   //return true, default ctor is always non-throwing 
      
        void func() noexcept{}
        noexcept(func());     //returns true
        void fake_noexcept() noexcept{std::throw -1; }
        noexcept(fake_noexcept())     //still return true, because noexcept just checks the compile time guarantee of things. run-time doesn't matter. 
      
        void no_gurantee_func(){}
        noexcept(no_gurantee_func());     //return false
    • If there IS one exception coming out of a function declared noexcept, then std::terminate is called, no stack-unwinding is called.
    • C++98 style:
      int lol(params)throw();
      int lol(params)noexcept; 
  • exception safety levels:

    • no fail: function never fails, such as std::move, std::swap, erase, unique_ptr operations,
    • no throw: it might be able to fail, but no exception is emitted, like: destructors, memory deallcation, cleanup functions.
    • strong guarantee: exception can emit, but no memory leaks, program state will remain unchaged.
  • Usage

    • to permit a function to/not to propagate exeptions
       void bar2 () noexcept{throw std::runtime_error("lol"); }
       void foo() noexcept(0==1) {throw std::runtime_error("oops"); }  //this is always going to propagate, as 0==1 is false, so we don't switch on noexcept
       void bar() noexcept(1==1){throw std::runtime_error("oops"); }   // always no exception emitted from ths function. equivalent to bar2. 
    • Actually, std::vector, and other STL containers, do need NOEXCEPT for move semantics; otherwise, copy is used SO DECLARE YOUR MOVE CTOR noexcept, if you're sure!!!
    • std::vector, std::deque, has insert, push_back... they all make "strong exception gurantee ": it's okay to fail, but the programs state will be restored.
    • With non-noexcept copy ctor, this is achievable: you copy all vector elements back to their original location.m
    • But move is different: once you've moved an obj, moving the objects back to their locations might yield problems too.
  • Cautions:

    • It's easy to add noexcept at the beginning, but it's hard to take it off, as it's part of the interface. your clients will rely on this.
    • If you're not sure whether to include it, just don't

std::exceptions

  1. run_time error
    #include <exception>
    try
    {
        if (badThingHappened)
        {
             throw std::runtime_error("Something Bad happened here");
        }
    }
    catch(std::exception const& e)
    {
        std::cout << "Exception: " << e.what() << "\n";
    } 

Misc

  • ' (C++14) int i = 100'000;
  • automatic variable: allocates and deallocates automatically when flows in/out of a scope.
    • other types include static and dynamic
    • with optimization, "stack variables" may not live on the stack. Instead they're in registers. ========================================================================

non-STL Tool functions

========================================================================

  1. static_cast: your compilation will fail, if bool (has to be available during compile time) is false (c++ 11)
    static_assert(1>2, "hehe");   //error: static assertion failed: hehe
    • Pros: better than #error, because static_assert happens after pre-processing
    • Cons: requires constexpr. To enforce that, need to be in a template function.
      template<typename T>
      void callback_check(const ConnectorClientCallbacks& cbs){
          static_assert(cbs.fill_discovery_msg != nullptr, "Discovery Client: fill_discovery_msg is required from both sub and pub");
      }
  2. Can executables compiled in c++11 use a library compiled with c++20? compile using C++20 the whole thing
    • -O3 is an optimization

macros

  1. What is a macro: it looks a like a function, but processed during compile time (scripted derivative). Why does it exist: because this is from C. #define square(x) x*x

    • or if you need to have more lines
       #define cube(x) x * \
          x * x
      
  2. It's dangerous, because it is a simple substitution. example:

    int a = 3; 
    square(a+2);        // you think it will be (3+2) * (3+2), but actually it will output 3 + 2 * 3 + 2, because it's simple substitution. one fix is #define square(x) (x)*(x)
    • The first step is a simple string substitution, no semantic testing
  3. Macro invokation do not need ; at the very end. So you want to use that as a distinction from regular functions. Also, name is mSOMETHING(). Otherwise, you might get funny compilation msgs.

  4. What do you do instead? use inline functions.

    • Inline func is also expanded at the time you invoke it. But Inline is processed by compiler (compilation), while macro is expanded by pre-processor.
      • the function is copied and expanded to the function call.
    • Inline can access all members in a class, macros do not.
    • Short class member functions will automatically go onto inline.

Bit manipulation

  1. basic
#include<bits/stdc++.h>
std::bitset<16>bin_num(integer); 
bin_num.count();        //# of 1s
  • i = (i<<2); Don't forget that i<<2 cannot modify i!!
  1. Bit field: Can effectively reduce the size of a struct. coming from C
// C
struct {
 unsigned int age : 3;    //only 3 bits long
} Age;

int main(){
  Age.age = 4;    // will get 4
  Age.age = 8;    // will get 0
}   

//C++
Age A; 
A.age ... 

c functions

  • memset

    #include <cstring>
    memset(void *str, int ch, size_t n);  Copies n char to str. 
    • undefined behaviours:
    • if n is greater than what str can hold
      • ch cannot be copiable (like not a c struct, array, scalar)
      • DO NOT USE THIS IN INT ARRAYS!!! it works by writing byte by byte, (int has 4 bytes, so you only want to write once!!)
  • memcpy (void* destination, void* src, size_t num); //copies value directly.

  • cmath functions: std::pow, std::log2

    #include<climits> INT_MIN; 
    #include<cmath> 
    std::pow(2, n); //2^n 
    log2(bin_num)           //the most significan bit. 
    
    #include<cstring> std::memset;
    printf("%u, %lu, %c", unsigned, long_unsigned, char); 
  • Logging:

    • FILE, FUNCTION are useful for generating logs
    • they're macros
      #include<iostream>
      using namespace std;
      int errorLog (const char* file, const std::string& msg){
         cerr << "[" << file << "] " << msg << endl;
      }
      #define LOG( msg ) errorLog( __FILE__, msg )
      main() {
         LOG("This is a dummy error");
      }
  • Sleep

    #include <unistd.h>
    sleep(10);    //sleep for 10 seconds

========================================================================

System commands

========================================================================

  1. exit
  • exit() exits the whole program, where return just returns to the caller stack. exit(0) means successful, exit(1) means unsuccessful.
  1. X86 uses little endian, some ARM uses big Endian

========================================================================

Common Error Messages

========================================================================

  1. segfault

    • might caused by infinite loop (stack overflow). weird thing is step will return segfault even if an infinite loop is not here but behind it
    • You may not have a constructor for your input.
    • pointer might be null. So a good habbit is to always do a pointer check
  2. expected initializer before - You might have forgotten a ";"

  3. undefined reference to some function:

    • 有可能是你namespace 没搞对
    • compiler 不兼容
    • 还有就是input type 不对,比方说geometry_msgs::TransformStamped 放到geometry_msgs::Transform 里边。 
  4. xx does not name a type

    • check if CMakeList.txt has properly imported it
    • check if your header has included it (your header file may be wrong!!)
    • check if you already have a namespace.
  5. colon : is used when you have

    • a constructor, you need to initialize it
    • inheritance
  6. vector v(3);, not v{3}! that's initializer.

  7. SUPER TRICKY: do not do (unsigned int i = 2; i >= 0 --i). because once i is below 0, it will actually be 4294......! use int instead for all i.
    . class{}**;**

    • I need to specifically do: mtx_ptr_(std:: make_uniquestd::mutex) to allocate resources in constructor?
  8. constness

    • **always have const member functions, so you can have const objects. Inside those const functions, make sure you use const member functions. **
    • Else you may see an error like this image
    • you don't need all members variables to be const if you wanna have const object.
  9. "Implicit declaration of function": you're missing a function declaration in .h file

  10. Do not have the same variable and function name!! Else they'll be mixed

  11. When you see _Allocator..., you should know this is vector resizing.

  12. Invalid use of incomplete type - you must include <.h> file, otherwise you see the error

    • Incomplete type: type whose size cannot be determined.
    • to create an incomplete type:
        struct student*ps; 
    • Declare the same type later.
  13. multiple definition: (see c++ compilation)

  14. when you do cout<<some_unsigned_char, it may not be displayed! Need to convert it to int

  15. error: invalid use of destructor '~util::Camera_Streamer' as a type

    • You might have ~Camera_Streamer::Camera_Streamer() {}
    • Correction will be Camera_Streamer::~Camera_Streamer() {}
  16. invalid declarator before '&' token - maybe you forgot namespace in namespace::func()

    1. double best_possible_d = 0;: must have initialization, else pod won't initialize!

========================================================================

Reminders

========================================================================

  1. reminder: pass in this->member in to a function object, like
    auto future = std::async(&File_Writer::async_file_write, this, std::reference_wrapper<Buf_Ptr>(this->buffer_), true);
    • std::async(func) needs func to be copyable - therefore if you have a moveable-only object, store it as reference
  2. std::accumulate(beg, end, init), defined in <numeric>
  3. remove(file) in <cstdio>
  4. if std::istream is not closed, next time open() will not succeed!!

========================================================================

Lesson

========================================================================

  1. check type if you don't get what you want: bool a = 10; //ofc you don't get the right thing

LEETCODE tricks

  1. Do not use memset.
  2. str.substr is powerful.
  3. heap overflow means you're trying to access a non-existent arr element.
⚠️ **GitHub.com Fallback** ⚠️