Skip to content

Instantly share code, notes, and snippets.

@cbsmith
Last active December 16, 2015 02:19
Show Gist options
  • Save cbsmith/5361634 to your computer and use it in GitHub Desktop.
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…
// -*- 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