Gergelim

How to Start a TypeScript Project on Node.js

written by Gian on 2018-06-13

In this post, I'll describe a quick setup to start hacking on a TypeScript project on Node.js, using yarn as package manager instead of npm. I'll use an app called readnext as example.

Setup

Create a directory and initialize yarn:

mkdir readnext
cd readnext
yarn init

To add dependencies, use yarn add:

yarn add tsc
yarn add typescript
yarn add typescript-eslint-parser
yarn add express
yarn add ts-node  # for live compile+run
yarn add nodemon  # will invoke ts-node when a file changes

We will use ts-node and nodemon to automate the restart of the application when we make changes. This will recompile the source and launch nodemon to keep looking for changes (as suggested in tdd). Tweak package.json to include "scripts":

"scripts": {
    "start": "npm run build:live",
    "build:live": "nodemon --exec ./node_modules/.bin/ts-node -- ./server.ts"
  }

(Oh, and now it would be a good time to init a git repo: git init. Add server.ts, tsconfig.json, package.json, and yarn.lock.)

Aside: Where is tsc?

If you do which tsc you'll get nothing; it's because tsc is actually inside ./node_modules/tsc/bin/tsc. Update (2019-01-07): you can run it without worrying about the exact location by running npx tsc instead.

Develop

Start the server with yarn start. Every time a file is changed, localhost:3000 will change (reload to make that happen).

Designing Data-Intensive Applications, by Martin Kleppmann (5/10)

written by Gian on 2018-02-17

This book is a survey of the staggering amount of pieces of technology that can be used to build data-intensive applications, defined (in my rough interpretation) as user-facing systems that treat significant amounts of data and are expected to do it quickly. Contains reflections on trade-offs to take into account when choosing one solution over the other.

Recommended to...

Read this if you work with distributed systems and want a fairly exhaustive overview of what's going on in your codebase. If you know your (Apache) Kafka and your Hadoop and your ZooKeeper, you might as well spend your time in better reads.

A somehow longer version

The undeniable merit of this book is to bring together in a reasonable space a wealth of research on distributed systems. Allow me a hazardous analogy. Reading about NP-hard problems makes you aware that there's a class of problems that you can't solve efficiently, unless you come up with an improvement on the state of the art; reading this book helps you get acquainted (I won't say familiar) with situations in which a problem is hard and/or has been solved using a given class of technology.

In general, I don't like surveys. They're sometimes very useful though.

I don't like them because the bad ones tend to fall into what could be called the shopping list trap: just keep listing names to show that you've done your research. "Problem X is hard. Product 1 solves it by using methodology M, but gives up on this functionality; product 2 offers it but lacks this other feature. My dear friend at company C integrates 1 and 2 and offers this, but then your circumstances might not require the expense." Sounds familiar?

But surveys are sometimes very useful, because you get exposed to lots of ideas, and hopefully you'll be able to recognize a problem when you see it and know how to look for a piece of software that solves it (a shopping list might be useful in that case), or you know that you need to write one.

I consider this book a rather good survey. I've read my fair share about problems in distributed systems before, but I was lacking the bird's eye view that is very important, and that you acquire only after much experience. I don't really believe in condensing experience, but this book is a good attempt at that. You still need to sweat blood on real systems in order to appreciate the beasts you're dealing with.

The last chapter was horribly hard to read. The idea of giving a personal interpretation of trends is commendable, but in this case, the execution just felt unnecessarily heavy. Then, an unexpected and appreciated reflection on the surveillance state in the very last section of the book, which is an eye-opener. If it wasn't for that, you could skip that chapter. (Well you still can, and only read that section.)

Notes on Amazon ECS

written by Gian on 2018-01-30

Here are some notes I've taken while reading Building Blocks of Amazon ECS.

Regions and Availability Zones (AZs)

AWS is divided into regions.

A region is divided into (≥ 2) Availability Zones.

To get more availability, deploy a service over multiple AZs.

Containers

A container virtualizes an operating system, while a Virtual Machine virtualizes physical hardware. This means that a container is not a VM.

A (container) image is a package that groups

Images can be deployed on any host machine. The container takes care of the communication with the host.

ECS allows running containerized applications on a cluster of EC2 instances (that are the containers' hosts). ECS works natively with Docker containers.

Container instances

An ECS instance is a special EC2 instance that

An ECS task is a group of containers. They logically belong together in order to make up an application/system. Tasks are not created directly, but through a task definition, that declares which containers belong to the task.

The ECS container agent is a program that handles communication between the (ECS) scheduler (the component that manages the ECS tasks) and the ECS instances. The ECS scheduler decides on which instance a container runs, according to some user-specifiable constraints.

An ECS cluster is a group of container instances inside a region (but possibly, and preferably, across multiple AZs).

To register an instance in a cluster, the instance needs an agent running.

Services

A service is a way of automating the concept of what to run. Conceptually, it looks like: "I want N tasks, defined by task definition D". This recipe is processed by the ECS infrastructure, that makes sure that those tasks are running, possibly restarting them if they go down.

Generating gergel.im Using Hexo

written by Gian on 2017-12-10

I've changed the static site generator that powers www.gergel.im. In this post, I explain the motivation behind this change, describe a few issue I had during the setup, and finally spend a word about my new workflow for content creation.

Motivation

The time I dedicate to Racket is too small by now, so for a while I have decided to drop Frog, the generator I've been using until recently. Also, since my interest has switched to JavaScript, I thought it would be a neat idea to find a JS-based generator. This is how I ran into Hexo.

I have grabbed the opportunity to transform the website more into my presentation to the world, stressing the fact that it's my personal page.

Setup

Migrating has been painfully manual, but also surprisingly straightforward. I blame especially my laziness. For instance, for each post, Frog requires a front matter in the form (notice the 4 spaces in front of each line):

    Title: A good title
    Date: YYYY-MM-DDThh:mm:ss
    Tags: tag-1, tag-2, ..., tag-n

To comply with Hexo's format, I needed to switch to yml (notice the termination with triple-dash and the change of date format):

title: A good title
date: YYYY/MM/DD hh:mm:ss
tags:
- tag-1
- tag-2
...
- tag-n
--

Only after doing it maybe fifteen times (I have roughly 25 posts) I started thinking about how vim could help me speed that up.

I spent a bit of time trying to figure out how to lay out the folder structure so as to have a blog inside a website. This can be achieved by using the index_generator[path] property in _config.yml, while keeping the root to my webpage to /:

url: https://www.gergel.im/
root: /
index_generator:
  path: 'blog'
  per_page: 10
  order_by: -date

Apart from this, laying out the files was pretty easy.

Workflow

I deploy the website using the git deployer. This takes the content of the generated public folder, copies it into another folder (don't know why), and pushes it to master. To also keep track of the source files, I created a develop branch. This means that I don't control master from my machine, but rather let the deployer push to it, and from time to time I just pull from my repository to have a local master in sync. I don't even need to do that, since I won't make any manual change to this branch. The only reason it's there, actually, is that GitHub Pages for users require that the content in master be rendered (unlike project pages).

My workflow for writing posts is now the following:

  1. checkout develop (usually I'm there already)
  2. hexo generate --watch to generate files when changing anything in the repository
  3. hexo server to check the results
  4. write content in source/_posts/a-title.md

At this point, if I go to localhost:4000/blog/<permalink structure>/a-title/, I can see the resulting page. When I'm happy with it, I do:

  1. commit changes to develop: git ci -am'Some message'
  2. push to origin/develop
  3. hexo clean and then hexo deploy

The resulting code is stored on GitHub, feel free to inspect it in case it might help you with your own setup.

Switching gergel.im to https

written by Gian on 2017-02-01

Today I ran into an article by one Troy Hunt that talks about the fact that https is now past the status of exception, and is becoming the new norm.

Not long ago, I had thought about switching this website to the secure protocol, but was intimidated by the prospect of work and bureaucracy that I needed to get into. Troy's post was enough to make me give it a serious try; I must admit, it was so much simpler than I expected, that I could easily have done it earlier.

Apparently, GitHub pages allows you to automatically switch to https, if you don't use a custom domain name, but yourname.github.io. Come on, GH! I was so close! As the most astute reader might suspect, I do use a custom domain name. What to do?

I googled a bit more and found this page (kudos!), that introduced me to the amazing Cloudflare, that offers a zillion of services to improve websites (I was impressed by the CDN that serves your page faster). The pricing plans for businesses appear intimidating, but for personal web pages, they have a free one. I was sold on the spot!

I needed to change the DNS on my domain registrar, and everything was setup, but, uh, my website itself.

I went through all the links, and removed the http: and https: parts. This works ── I didn't know. I also included the simple script found in the post above, to redirect anything to https that comes from http.

And the trick is done! Gergel.im is now served via https.

Destructors Are Not Always Called in Case of Exceptions!

written by Gian on 2016-06-05

Wrong assumption: when an exception occurs, a stack unwinding occurs, which means that the relevant destructors of objects are called in the appropriate order.

My wrong assumption

Suppose we have this snippet:

struct A {
    [[ noreturn ]] void op() { throw 1; }
    ~A() { std::cout << "Deleting obj...\n"; }
};

int main() {
  A a;
  a.op();   // The dtor might never be called!
}

Is a's destructor called when the exception is thrown? I thought so; I was wrong. This is the output of the snippet above:

terminate called after throwing an instance of 'int'
Aborted (core dumped)

Explanation

When op() is called, the exception is thrown, and there is no handle for it; it gets out of the main function, so that std::terminate is called and the program aborts (see this question on StackOverflow). From the standard ([except.throw]):

When an exception is thrown, control is transferred to the nearest handler with a matching type; "nearest" means the handler for which the compound-statement or ctor-initializer following the try keyword was most recently entered by the thread of control and not yet exited.

and later on:

If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined

Correction

A way to have this exception handled is to wrap the construction of A and the call to op() into a try block:

struct A {
    [[ noreturn ]] void op() { throw 1; }
    ~A() { std::cout << "Deleting obj...\n"; }
};

int main() {
  try {
    A a;
    a.op();   // the dtor is guaranteed to be called
  } catch(...) {
    throw;
  }
}
Deleting obj...
terminate called after throwing an instance of 'int'
Aborted (core dumped)

Notice that just putting the constructor of A out of the try gets us back to the destructor not being called! Read carefully the first snippet from the standard:

... "nearest" means the handler for which the compound-statement or ctor-initializer following the try keyword.

So if we had:

// This might not call the dtor!
int main() {
  A a;
  try {
    a.op();
  } catch(...) {
    throw;
  }
}

there would be no ctor-initializer (nor compound-statement, but that wasn't there before either) after the try.

Apparently, whether or not the stack is unwound is implementation-defined, meaning that on other configurations the result of my experiment wouldn't be the same. But why risking?

How to Write a CGI Program

written by Gian on 2016-06-05

Today I wanted to make some experiments with CGI on my newly-installed Ubuntu 16.04. There are a few steps to take before starting to experiment, and I'm writing them down here in case anyone else wants to try something similar.

TL;DR

  1. sudo a2enmod cgi
  2. Write program, build, copy it into /usr/lib/cgi-bin
  3. sudo chmod a+x <yourprogram>
  4. Go to localhost/cgi-bin/<yourprogram>
  5. Enjoy

Make sure your first line of output is Content-type: text/plain\n\n, and you should be fine.

Configure Apache

On Ubuntu, the main configuration for apache lies in the directory /etc/sites-available/000-default.conf. The principle is that you have a bunch of configurations available, and a subset of them that are also enabled. Enabling a configuration means simply that a symlink to some file in the sites-available gets created in sites-enabled. Rather than doing this manually, the Apache documentation encourages to use a command, a2enconf. Which, well, does exactly that: creates the symlink.

In the same spirit, you use a command a2enmod to enable modules. Point is, the CGI module is not enabled by default; to turn it on, all you need is one sudo a2enmod cgi command away. Note: you might receive a warning, saying that you are using a multithreaded MPM, in which case this command will be automatically translated into sudo a2enmod cgid (notice the final d).

When you enable a module, you are asked to restart (not reload) the server:

sudo service apache2 restart

Write the program

The program needs to respect the directions given in the official RFC. What? Too long, you say? Well, to get started, you only need to make sure to declare, as the first line of your output, the content type you are about to produce, followed by a blank line. According to HTTP, what you are doing is providing an HTTP Response header, which is the only one you have to provide explicitly. You then need a blank line that indicates that you are done with the response headers; what comes next is then the Response body.

So for example, here is a silly Hello, world program:

#include <iostream>

using namespace std;

int main() {
    cout << "Content-type: text/plain\n\n";
    cout << "Hello, world!\n";
    return 0;
}

Run it!

Build this program and save the executable in the directory /usr/lib/cgi-bin/. This path is defined in one of the enabled configurations (usually under /etc/apache2/conf-enabled/), which is aptly named serve-cgi-bin.conf. Make sure to give permissions to execute the program (sudo chmod a+x <yourfile> should suffice). At this point, just open your browser at localhost/cgi-bin/hello (where hello is the name you actually gave too your executable program), and you should be able to see a page displaying the friendly greeting.

Writing a Simple Calculator in Racket

written by Gian on 2015-12-06

Frustrated by several attempts at creating GUI-based programs that I've tried in the past, I decided to try how differently the story could end when using a language that promises enlightenment to its users. I ended up writing Calculon, a simple calculator, and in the process learned a couple of things about Racket and the racket/gui module (and paid homage to one of the best cartoons in history).

The racket/gui module

The module which I used for the GUI is called, as was to be expected, racket/gui. I have read a bit of the tutorial to understand the basic philosophy, and I was ready to start hacking.

The principle is simple: there are some window objects which work as containers, that in turn contain elements (like buttons, menus, other containers, you name it). In the beginning, I wrote everything in a single source file, but later it was easy to factor out the pieces and I happily ended up with three parts:

  1. The GUI itself
  2. The expression parser
  3. The test module

Let's tear them down to see what's inside.

The GUI

I wanted to have a basic layout for my calculator, so I thought to have the classic matrix of buttons with the digits, the operations, and the decimal point, to which at the end I added a reset button.

calculator-layout

The display is only for output, and shows what the user inserts by clicking the buttons (which actually is rather annoying, but limits a lot error management, since we almost completely control the input).

We start by defining a generic container known as frame, inside which we start putting the display:

(define frame (new frame% [label "Calculon"]))

(define display$ (new text-field%
                      (label "")
                      (parent frame)
                      (init-value "0")))

The parent-child relationship is quite important and just describes who owns whom (or who belongs to whom): in this case, we say that the display$ objct belongs to the frame.

At this point, the building block is the horizontal-panel%, whose role is to provide an area to group elements horizontally (in this case, the buttons). So for the first row, we have the following:

;; Row 0: ? ? sqrt C
(define row0 (new horizontal-panel% [parent frame]))
(new button% [parent row0]
     [label ""]
     [min-width 30]
     [enabled #f])
(new button% [parent row0]
     [label ""]
     [min-width 30]
     [enabled #f])
(new button% [parent row0]
     [label ""]
     [min-width 30]
     [enabled #f])
(new button% [parent row0]
     [label "R"]
     [min-width 30]
     [callback (λ (b e)
                 (send display$ set-value "0"))])

Man I love this language. Can it get easier than that? You have a line and you get buttons inside. Each button has a label, can be disabled, can be set to a minimum width, and can be associated to a callback (that takes as arguments the button object itself and the event). Buttons belong to the row, which in turn belongs to the frame.

After we finish listing the rows, we show the frame itself:

(send frame show #t)

This is general syntax for object methods call: send means Call the method show of the object frame. The display shown above works the same way: Call the method set-value of the display$ object.

GUI-related functions

After some refactoring, I left only 2 functions inside the GUI module:

;; GUI-related functions
;; Push a button of an operation (+, -, ...)
(define (push-operation op)
  (send display$ set-value (string-append (send display$ get-value) op)))

;; Push a button which is not an op (digit, decimal value)
(define (push-number button-value)
  (define current-display (send display$ get-value))
  (define result
    (match current-display
      [(regexp #rx"^0") button-value]
      [_ (string-append current-display button-value)]))
  (send display$ set-value result))

The first one just takes the operation button we have just pressed, and created a string to send to the display. The second introduces a possibly useless complication coming from the fact that I want the initial 0 to be substituted by the first digit the user inserts. It uses my favorite function, match, to apply a regular expression to what is currently in the display: if it starts with 0, just substitute it with the button value (buttons in this case are only digit buttons); otherwise, just append.

The expression parser

The expression parser is invoked as a callback of the = button, and takes whatever is on the display to try and evaluate it, returning the result of the evaluation.

(define (push-equal expr)
   (define ops-lst (regexp-match
                    #px"(\\d+[./]?\\d*)\\s*([-÷+×])\\s*(\\d+[./]?\\d*)"
                    expr))
   (define result 0)
   (match ops-lst
     [(list _ x f y)
      (number->string ((string->f f)
                       (string->number x)
                       (string->number y)))]
     [_ (raise exn:fail:user)]))

In this case, we just match the expressions of the form dictated by the (rather cumbersome) regular expression on line 3. It is actually very basic, after all the escaping is stripped; it takes also into account that Racket uses fractions when it can to display fractional numbers, and this is why I need to match both the decimal point (which is one of the possible buttons) and the '/' character of a fraction.

The match function shines even brighter here: if what I match is of the form of a list of 3 elements x f y, then assume that f is an operation and apply it to the operands x and y.

Testing

No piece of software can be considered complete without a proper unit test module. I am pretty happy with the layout I have found for the testing modules of my Racket projects, so I'll paste it here and try to explain in detail:

#lang racket

(require rackunit
         rackunit/text-ui
         "calculon.rkt")

(module+ test
  (define suite
    (test-suite
     "calculon: callback tests"

     (test-case
      "Check equal callback"
      (check-equal? (push-equal "8+5") "13")
      (check-equal? (push-equal "12.11  - 14.03") "-1.92")
      ;(check-equal? (push-equal "4/5 * 3") "12/5")  ; FIXME
      ;(check-equal? (push-equal "20/3 * 1/5") "10.0") ; FIXME
      )))
  (run-tests suite))

Notice first the require list: apart from the obvious modules for testing, I only require the expression parser. The more GUI-related function are not interesting for testing, since they only make easy transformations to their input for displaying purposes. However, testing the parser is very useful, as frees us from testing manually via pressing the buttons to try out the few operations that we want to test.

I write a separate Racket module that I call test ((module+ test) means Add what follows to the module called test. Modules are an amazing mechanism and one of their feature is the ability to span several source files). Inside the module, I define a test-suite, which is just a collection of test cases (in this case, only one). Now inside the test-case, I call repeatedly check-equal? to compare the result of the call to push-equal with the result I expect. I can run it separately in DrRacket by just pushing Run, or from the command line by issuing raco test calculon-test.rkt:

  $ raco test calculon-test.rkt
  raco test: (submod "calculon-test.rkt" test)
  1 success(es) 0 failure(s) 0 error(s) 1 test(s) run
  0
  2 tests passed

Conclusion

I am very happy with the result. It is simple, but also it didn't take much time, and I have used a GUI in a program of mine for the first time. The complete project lives on GitHub; feel free to mail me your thoughts and to contribute to it.

Twelve weeks of Racket and CS:APP

written by Gian on 2015-11-17

As promised, this is a wrap up of my experience concentrating for (slightly more than) 12 weeks on only 2 subjects. For this first stint, I chose to learn Racket and to read Computer Systems: A Programmer's Perspective. Not long ago I have lost interest in providing ultimate motivations for what I do in my free time; I'll just stick to what happened. (I can't promise I won't motivate everything else, which is not ultimate.)

Starting Racket, and why I will go on

Racket is sensational. Historically, I have come from C++ and object-oriented programming, which turned into a love for Java, only to then run away disgusted, full of awe before the purity of C (sic). Functional programming is something I have run into only after my college graduation, and for a few years, it remained a buzzword in the back of my head reminding me of something I wanted, one day, to try.

Some time ago, I read a very enthusiastic post on Racket, who got me excited. Since roughly the end of August, I have dedicated 45 minutes a day, every working day, to learn Racket. I've done a few things, and I am amazed of that, even though it might seem peanuts to the casual reader (and maybe to the causal one too).

Great community, early contributions

I knew that the Haskell community was very welcoming; I can say the same of the Racket one. I'll give an example. I have found these (supposedly) easy Intro projects to get my feet wet, and I saw someone posting his very first experiences with Racket on the Google group, so I picked one of the projects (I wrote a very simple program for finding anagrams), and posted on the group only to say that. A few hours later, I get a reply from Greg Hendershott, a very kind person with lots of impressive contributions to the community, among which Frog, a blog software written (obviously) in Racket, and Fear of the macros, a great reading on Racket macros.

I have also contributed a couple of patches to the Racket's track of exercism.io, having the chance to collaborate with other spectacular people who managed to suggest me a couple of very instructive improvements on my code.

I will also cite my good experience with HackerRank's functional programming challenges, who made me try the basics and keeps me company when I want to do some katas.

The way people can use Racket is awe-inspiring

The Racket Way has impressed me. Imagine a language with which you can do everything, including slides for presentations and writing books. A language that gives you the chance to write other languages, which are still Racket, no, a Racket, that you can use to other things.

With C++, no, actually with any Turing-complete language, you could do everything. To the risk of repeating what other more brilliant people have already said with better-chosen words, however, it is not the same to write something in assembly or in Python.

But there's more. Here's a personal anecdote: I have intermittently written software in OO languages since 2000, and have never been able to write something with a GUI. I know, it's silly; I could've taken the time to try. I did. Several times. I have tried Qt, then wxWidgets with C++; then said to myself, why not Python? I don't want to write a lot of boilerplate code, I want just to see a damn thing on the screen. Maybe I wasn't constant enough on these endeavors; but after a week of reading and trying, if you only see the result of some tutorial on the screen, and you are not creating your own thing yet, you start getting demotivated.

This morning in 50 minutes I have written a basic, buggy calculator in Racket.

Racket: approved!

I have this dream of being able to write purely functional programs not so late from now (whatever that means!). And I am amazed at the possibilities. This is why I have decided to use Racket for another 12 weeks.

CS:APP, and why I'll do something else instead

(My interpretation of) the promise of Computer Systems: A Programmer's Perspective is quite captivating: revise your knowledge of the whole system, concentrating more on which aspects impact a programmer writing his program.

The book starts from a general introduction to systems, and then progresses from arithmetic representation to assembly to processor design, up until virtual memory, concurrency, and other high-level constructs.

I was thrilled because during my last job search I have run often into the wall of "Design a possibly big system made by interconnected subsystems, to solve problem X", which is a skill I feel I don't own yet. The foreword of the book and the index got me hooked, as I thought that a good revision would do me good and teach me the skill.

Why I stopped

I think I can no doubt learn this skill, but not by reading a book; or at least, not only. What I need is direct experience building systems, which is exactly what I am doing now.

It is of no use to read about virtual memory, like I did in college, and never try to write a virtual memory system for the need of it. Nothing is comparable to the way we learn when in real need. At that point, maybe after the mess that got to the delivery of a product, I might consider reading an well-organized treatise, that would then click with steps I followed in a totally different order, possibly with a totally different focus.

The book is just great; it is not for me now though. If I want to focus on concurrency, I read a book on concurrency and at the same time I work on a project using it. I have found no other method working for me. In other words, I only have praises for a book; but it is only a book.

The next 12 weeks

These first 12 weeks started somewhere in late August and officially ended on November 8. I'm not sure I'll start 12 more right away, since I am in a peculiar time of the year, and I'll have to stop 3 weeks for vacation at some point.

The plan so far is to fill this time with a lot of Racket and as much thinking, and come up with a project I want to focus on for the next 12-weeks stretch.

Track the Lifetime of std Classes' Instances

written by Gian on 2015-11-03

I remembered a simple trick I used to know, but that could not remember on the spot, to solve a problem in understanding the exact lifetime of C++ objects.

Problem statement

Reading about unique_ptr's, I have found some issue trying to understand the exact lifetime of objects of such types. When is the ownership of a unique_ptr exactly yielded? What happens when the first one passes its ownership?

A bad idea

I have gone through a silly phase where I have thought that I could log messages at crucial moments of the objects' lifetime by just writing to standard output in constructors, destructors, copy/move constructors, and copy/move assignment operators. The first idea is to wrap such functions in the object being passed as argument to the unique_ptr:

struct S {
    S() { cout << "S()\n"; }

    /*
     * These will never be called, since what we are
     * copying/moving is the unique_ptr. How do we
     * extend a unique_ptr to print its
     * creation/destruction times?
     */
    S(const S& s) {
      cout << "S(const S& s)" << hex << &s << "\n";
    }

    S(S&& s) {
      cout << "S(S&& s)" << hex << &s << "\n";
    }

    ~S() { cout << "~S()\n"; }
};

I even have the naive question expressed in a comment. Of course this wouldn't work. While this approach does work when you want to follow the structure S's lifetime, it certainly doesn't when you want to follow the lifetime of the wrapping smart pointer.

I banged my head against Google and ran into some unrelated threads on StackOverflow. No one ever had this problem before? There must be something terribly wrong with what I am looking for...

How can we do better?

At the end of my study session, I thought about the obvious:

Just wrap the unique_ptr in a structure, and print a message in this structure's ctors, dtors, and copy/move ctors and assignment operators

So I separated my code out into a header, and used it instead:

#include <memory>
#include <iostream>
#include <iomanip>

// Instrument a unique_ptr with some logging, to follow its
// lifetime.
template <typename T>
struct unique {
    unique() : _p(nullptr) {
        std::cout << "unique() " << std::hex << &_p << "\n";
    }

    unique(T* p) : _p(p) {
        std::cout << "unique(T* p) " << std::hex <<
          &_p << "\n";
    }

    unique(const unique<T>& p) : _p(p._p) {
        std::cout << "unique(const unique& u) " <<
          std::hex << &_p << "\n";
    }

    unique(unique<T>&& u) : _p(move(u._p)) {
        std::cout << "unique(unique<T>&& u) " <<
          std::hex << &_p << "\n";
    }

    // Can't declare this, as unique_ptr's operator= with
    // copy semantics has been explicitly deleted!
    unique<T>& operator=(const unique<T>& p) = delete;

    unique<T>& operator=(unique<T>&& p) {
        std::cout << "operator=(unique<T>&& p) " <<
          std::hex << &_p << "\n";
        _p = move(p._p);
        return *this;
    }

    ~unique() {
      std::cout << "~unique() " << std::hex << &_p << "\n";
    }

    std::unique_ptr<T> _p;
};

The basic structure of all of these functions is the following:

  1. Tell me your name
  2. Tell me the address of the unique_ptr

They really don't do much, but they are terribly useful when things get complicated. Which, given the language, is quite often.

Example

A very simple one:

#include <memory>
#include "../util/instr_ptr.hpp"

using namespace std;

unique<int> returnPtr() {
    return unique<int>(new int);
}

int main() {
  unique<int> u = returnPtr();
  cout << hex << &u << endl;
}

The output would be something as simple as:

  unique(T* p) 0x7fff71382e78
  0x7fff71382e78
  ~unique() 0x7fff71382e78

As I said, nothing complicated, but it helps.