Last active
December 16, 2015 02:19
-
-
Save cbsmith/5361634 to your computer and use it in GitHub Desktop.
A simple example of how it is perfectly reasonable to have a pointer that may or may not be nullptr, and therefore delete a pointer that may or may not be nullptr. We've got people of type Person who, when they get married, may choose to take on their spouse's last name. These people always have a given last name, called "lastname", but they may…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -*- compile-command: "clang++ -pedantic -g -O3 -o the_nullptr_story -std=c++0x -stdlib=libc++ the_nullptr_story.cpp" -*- | |
// Simple example of how it is perfectly reasonable to have a pointer that may or may not be nullptr, | |
// and therefore delete a pointer that may or may not be nullptr. | |
// Formatting is a bit unusual/dense to make it easy to focus on the important bits. | |
#include <string> | |
#include <ostream> | |
class Person { | |
public: | |
//Moved to the top so nobody misses it | |
~Person() { delete marriedname; } //could be nullptr if single or if they have not taken their spouse's name | |
using name_t = std::string; | |
Person(name_t given_firstname, name_t given_lastname) | |
: firstname(std::move(given_firstname)), lastname(std::move(given_lastname)) {} | |
//if you take a new name, there may be exceptions | |
void marry(const Person& spouse, name_t newname); | |
void marry(const Person& spouse) noexcept { married = true; } | |
//The rest of this class declaration is comparatively uninteresting | |
name_t get_birth_lastname() const { return lastname; } | |
name_t get_lastname() const { return (nullptr == marriedname) ? lastname: *marriedname; } | |
name_t get_firstname() const { return firstname; } | |
bool is_married() const noexcept { return married; } | |
std::ostream& format_on(std::ostream& s) const; //decorative bits | |
Person(const Person&) = delete; //we can't copy people!! [yet] | |
Person& operator=(const Person&) = delete; //people are irreplaceable! | |
private: | |
const name_t firstname; | |
const name_t lastname; | |
bool married = false; //no arranged marriages at birth! | |
const name_t* marriedname = nullptr; | |
}; | |
std::ostream& operator<<(std::ostream& s, const Person& p) { return p.format_on(s); } | |
std::ostream& Person::format_on(std::ostream& s) const | |
{ | |
s << firstname << ' '; | |
if (nullptr != marriedname) s << *marriedname << " née "; | |
return s << lastname; | |
} | |
void marry(Person& groom, Person& bride, bool keeping_lastname=false) | |
{ | |
if (keeping_lastname) | |
bride.marry(groom); | |
else | |
bride.marry(groom, groom.get_lastname()); | |
//we are now in an exception free zone | |
groom.marry(bride); | |
} | |
//***************************************************************** | |
// This function is the nut of it. * | |
// Marries another person and takes on a new name in the process. * | |
//***************************************************************** | |
void Person::marry(const Person& spouse, name_t newname) | |
{ | |
auto previousname(marriedname); | |
marriedname = new name_t(std::move(newname)); | |
delete previousname; //could be nullptr, but maybe this isn't their first time to this dance | |
marry(spouse); | |
} | |
//elsewhere in the 'verse... [this should be a separate file] | |
#include <iostream> | |
#ifdef IMPATIENT | |
static auto sleep_for_a_little_while = [] () {}; //time flies when you do nothing | |
#else | |
#include <thread> | |
#include <chrono> | |
static std::chrono::seconds a_little_while(1); | |
static auto sleep_for_a_little_while = [] () { std::this_thread::sleep_for(a_little_while); }; | |
#endif | |
using std::cout; | |
void the_story_of_fred_and_wilma() | |
{ | |
Person fred("Fred", "Flinstone"); | |
cout << fred << " is born.\n"; | |
sleep_for_a_little_while(); | |
Person wilma("Wilma", "Slaghoople"); | |
cout << wilma << " is born.\n"; | |
sleep_for_a_little_while(); | |
cout << fred << " and " << wilma << " meet.\n"; | |
sleep_for_a_little_while(); | |
cout << fred << " and " << wilma << " are dating.\n"; | |
sleep_for_a_little_while(); | |
cout << fred << " and " << wilma << " are engaged.\n"; | |
sleep_for_a_little_while(); | |
marry(fred, wilma); | |
cout << fred << " and " << wilma << " are now married.\n"; | |
} | |
void the_story_of_henry_and_lucy() | |
{ | |
Person lucy("Lucy", "Stone"); | |
cout << lucy << " is born.\n"; | |
sleep_for_a_little_while(); | |
Person henry("Henry", "Blackwell"); | |
cout << henry << " is born.\n"; | |
sleep_for_a_little_while(); | |
cout << henry << " notices " << lucy << " speaking at the Massachusetts legislature.\n"; | |
sleep_for_a_little_while(); | |
cout << henry << " asks for " << lucy << "'s hand, but is refused for years.\n"; | |
sleep_for_a_little_while(); | |
cout << "Huzzah! " << lucy << " agrees to marry " << henry << ".\n"; | |
sleep_for_a_little_while(); | |
marry(henry, lucy, true); | |
cout << henry << " and " << lucy << " are now married.\nMuch hand-wringing ensues.\n"; | |
} | |
int main(int argc, const char* argv[]) | |
{ | |
cout << "Our story begins...\n"; | |
the_story_of_fred_and_wilma(); | |
cout << "Several millenia pass...\n"; | |
sleep_for_a_little_while(); | |
the_story_of_henry_and_lucy(); | |
cout << "...and they all lived happily ever after, even if they did delete some nullptr's along the way. :-)" << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment