This project has been created as part of the 42 curriculum by baelgadi.
Memory allocation, pointers to members, references and switch statements
On Themyscira we trained with what we had.
We learned to use every weapon, to know its weight, when to hold it close and when to let it go.
A warrior who does not know the reach of her weapon is dangerous to herself.
C++ gives you 2 ways to hold memory: on the stack and on the heap.
CPP01 teaches you the difference.
|
CPP Module 01:
7 exercises. C++98 standard only. Compiler: c++ · Flags: -Wall -Wextra -Werror · Must compile with -std=c++98Exercise 00: BraiiiiiiinnnzzzZ · ex00/ · Stack vs heap zombieExercise 01: Moar brainz! · ex01/ · Heap array of objectsExercise 02: HI THIS IS BRAIN · ex02/ · References vs pointersExercise 03: Unnecessary violence · ex03/ · References as membersExercise 04: Sed is for losers · ex04/ · File I/O with streamsExercise 05: Harl 2.0 · ex05/ · Pointers to member functionsExercise 06: Harl filter · ex06/ · Switch statementForbidden: printf · *alloc · free · using namespace · friend · STL containers · STL algorithms |
A warrior’s spear thrown in training disappears when the session ends.
A sword forged and stored in the armory stays until someone puts it away.
| Stack | Heap | |
|---|---|---|
| How | Zombie z("Ares"); |
Zombie* z = new Zombie("Ares"); |
| Lifetime | Ends at closing } |
Until you call delete |
| Cleanup | Automatic | Manual (your responsibility) |
| Destructor called | Yes, automatically | Only when you delete |
void stackExample(void)
{
Zombie z("Steve"); // created here
} // destroyed here (destroyer called)
Zombie* heapExample(void)
{
return new Zombie("Ares"); // survives the function
} // must delete it or leaks[!WARNING] Every
newmust be paired with adelete. Everynew[]with adelete[].
A reference is an alias.
Not a copy, nor a pointer, rather the same thing, under a different name.
std::string weapon = "sword";
std::string &alias = weapon; // alias IS weapon
alias = "lasso"; // weapon is now "lasso"Compared to pointers:
| Pointer | Reference | |
|---|---|---|
| Syntax | int* p = &x; |
int& r = x; |
| Can be null | Yes | No |
| Can be reassigned | Yes | No (bound at declaration, forever) |
| Dereferencing | *p |
just r |
[!TIP] Use
const &when passing objects into functions you won’t modify as it avoids a copy without risking mutation.void logName(std::string const &name); // reads name, no copy made
A warrior is not just a body: she carries a set of moves.
You can point to the move itself and call it later.
class Harl {
public:
void complain(std::string level);
private:
void debug(void);
void info(void);
};
// A pointer to a member function of Harl that takes void and returns void
void (Harl::*ptr)(void) = &Harl::debug;
Harl h;
(h.*ptr)(); // calls h.debug()The syntax is unusual but it reads: “call ptr on object h.”
std::ifstream reads files. std::ofstream writes them.
Both work like std::cin / std::cout.
#include <fstream>
std::ifstream in("input.txt");
std::ofstream out("output.txt");
if (!in.is_open())
// handle error
std::string line;
while (std::getline(in, line))
out << line << "\n";[!NOTE] Both streams close automatically when they go out of scope, so n manual close is required.
Exercise 06 introduces switch.
switch (level)
{
case 0:
debug();
break; // without break, execution falls through to the next case
case 1:
info();
break;
default:
complain();
}Fallthrough is intentional in some designs.
Unintentional fallthrough is a bug that compilers won’t always catch.
Forgetting delete[] for arrays
Zombie* horde = new Zombie[n];
delete[] horde; // not delete hordeReturning a reference to a local variable
std::string& bad(void)
{
std::string local = "gone";
return local; // undefined behavior since local is destroyed after return
}Initializing a reference member outside the initialization list
Reference members must be initialized in the constructor initialization list.
You cannot assign them in the body
// WRONG !!!
HumanA::HumanA(std::string name, Weapon &weapon)
{
_weapon = weapon; // compile error if _weapon is a reference
}
// Right
HumanA::HumanA(std::string name, Weapon &weapon) : _weapon(weapon)
{
}# ──── ex00 ────
cd ex00 && make
./zombie
valgrind --leak-check=full ./zombie
# ──── ex01 ────
# All N zombies announce, all destroyed together
cd ex01 && make
./horde
valgrind --leak-check=full ./horde
# ──── ex02 ────
# Pointer and reference both point to the same string (Addresses match)
cd ex02 && make
./brain
# ──── ex03 ────
# HumanA always has a weapon. HumanB can exist without one.
cd ex03 && make
./violence
# ──── ex04 ────
cd ex04 && make
echo "The lasso reveals all truths." > test.txt
./sed_is_for_losers test.txt lasso "Lasso of Truth"
cat test.txt.replace
# ──── ex05 ────
cd ex05 && make
./harl DEBUG
./harl INFO
./harl WARNING
./harl ERROR
./harl NONSENSE # should produce no output or a default
# ──── ex06 ────
cd ex06 && make
./harlFilter DEBUG
./harlFilter WARNING
./harlFilter ERROR
./harlFilter NONSENSEnew and deletenew expressiondelete expressionswitch statementYou can convince yourself the leaks are small.
You can tell yourself you will fix them later.
Run Valgrind, and it will tell you the truth whether you want it or not.
The Lasso does not lie and neither does Valgrind.