Notes C++
Notes for C++
-
push_back()
vsemplace_back()
- copy vs move
- vec.insert({a, b}) vs vec.emplace(a, b)
-
const
vsconstexpr
-
const
: could be compile-time or runtime constants -
constexpr
: enforces compile-time constants. Fxns might still be runtime, check next point. - Any variable that should not be modifiable after initialization and whose initializer is known at compile-time should be declared as
constexpr
. - Any variable that should not be modifiable after initialization and whose initializer is not known at compile-time should be declared as
const
. - https://www.learncpp.com/cpp-tutorial/compile-time-constants-constant-expressions-and-constexpr/
- Don’t use
const
when passing by value. - Don’t use
const
when returning by value.
-
-
constexpr
andconsteval
. Link-
constexpr
- can be called by both compile-time and runtime functions.
- to ensure compile-time, capture the return value in a new constexpr variable.
-
consteval
: – C++20 –- cannot be called during runtime
- enforces compile-time call. Parameters should be constexpr.
-
- Lambda
- Variable initialisation.
- 3 ways:
- Copy (
=
) : Copy values. - Direct (
()
) : Direct initializer. - Brace (
{}
) : Direct list initializer.<--- use this
- Copy (
- Default value for uninitialised variable:
int a; // bad: undetermined. could be anything. int b(); // bad: interpreted as a function. Will return true! int c{}; // good: init to 0 int d{4.5}; // [error][but safer]. {} doesn't allow value which d can't hold. Doesn't drop '.5' automatically like other 2 methods string s; // empty string of size 0 i.e. s = ""
- 3 ways:
- Postfix operator has higher precedence than prefix operator.
*ptr++ // increment ptr but deref the un-incremented address
- Operators which are mainly used for their ‘side effects’ return their left operand. This allows chaining.
x = y = 5; // evaluates as x = (y = 5) cout << "Hello " << "world"; // evaluates as (std::cout << "Hello ") << "world!"
- Macros are bad:
- Can’t be treated as normal variables. So, hard time to debug with debuggers; would see the name & not the actual value. Debuggers ‘watch’ these variables.
- Don’t follow normal scoping rules; might end up getting used somewhere in the code!
- Risk of a variable being defined as a macro in some file.
- Vector
reserve()
vsresize()
vs nothing!:-
reserve
would allocate memory ahead of time. Capacity will be affected, not size. -
resize
would insert or delete elements. Size is affected. Capacity may not be if new size <= old capacity. - nothing would grow/double the vector when size>capacity. Required O(N) copying everytime!!
-
-
lvalue
vsrvalue
:-
lvalues
: variables/objects that persist beyond the end of the expression. -
rvalues
: literals or returned value of functions/operators that are discarded at the end of expression.
-
- pointers(*) vs reference(&): Great answer link
- pointer: First account forwarding to second account. The pointer itself has a memory location.
- name1@email.com -> name_surname@email.com
- reference: Alias of email. Both are same account; no separate memory.
- netID@uni.com, first.last@uni.com
- has to be initialised. can’t be reseated.
- pointer: First account forwarding to second account. The pointer itself has a memory location.
- L-value reference with
const
:int x { 50 }; const int y {100}; int& ref { x }; // valid: lvalue reference bound to a modifiable lvalue const int& const_ref {x}; // still valid // const_ref = 51 // invalid: can't change through const reference. x = 51; // valid: can be changed through non-const identifier cout << << ref << " " << const_ref << endl; // 51 51 int& ref_y { y }; // invalid: can't bind to a non-modifiable lvalue const int& ref_y_const {y}; // valid int& ref_rvalue {1}; // invalid: can't bind to an r-value. Else you'll try to modify 1 using the reference const int& ref_rvalue2 {1}; // valid: temporary object of rvalue is created.
-
const
ptr : compiler-explorer linkconst MyClass* ptr = &obj; MyClass* const ptr = &obj; const MyClass* const ptr = &obj; //read-only
-
unique_ptr
andshared_ptr
:- unique_ptr
- shared_ptr : multiple smart pointers share the same resource. Resource is deallocated when the last smart ptr goes out of scope (count==0)
- uses reference counting for control block.
- prefer make_shared. Combines resource + control into a sigle memory.
- Caution:
int decimal = 10; int binary = 0b1010; int hex = 0x1010; int octal = 010; // <-- prefix zero means Octal!!
- Python-like bindings:
for(auto [key, val]: my_map){ cout << key << ": " << val << '\n'; }
- Classes:
- Compiler Explorer code link
- Default access to members and methods is private
- classes with virtual functions maintain vtbl (virtual function table) to determine the function call
- Dynamic & Static cast:
if(TypeA* p = dynamic_cast<TypeA*>(ptr)){ cout << "ptr is of TypeA" << endl; } int a = static_cast<int>(3.4);
- Move vs Copy - Compiler Explorer, Quick C++ Benchmark