Skip to content
Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Pointer-to-member-functions can be tricky

elbeno, 31 August, 201831 August, 2018

Note: the following applies to Microsoft’s compiler only — not to GCC or Clang.

Pointers-to-member-functions (PMFs) are a bit off the beaten track in C++. They aren’t very syntactically pleasing, and they aren’t as easy to deal with as regular pointers-to-free-functions (PFFs). But they still see use, particularly in pre-C++11 codebases or where people choose to avoid the overhead of std::function or lambdas as template arguments.

Although idiosyncratic, the way Microsoft’s compiler implements PMFs is fairly well-known in its effects. Classes that use single inheritance can achieve PMFs the same size as PFFs, i.e. the size of a pointer. Classes that use multiple inheritance must use an implementation-defined structure, which is larger than a pointer.

This snippet of code illustrates the difference.

This has all been well-documented on Raymond Chen’s blog, The Old New Thing, for years now. But given the scarcity of PMF usage, subtle dangers still lurk.

One issue can arise when separating the definition of a PMF from its class. Let’s say we have a class defined in a header a.h:

class A
{
  // probably a reasonable size class; we're going to use 
  // PMFs for this class

  // multiple inheritance is rare, and this class doesn't 
  // use it, so PMFs for this class will be just the size
  // of a pointer
};

Because A is a fairly large class, we might have a forward declaration for A, either in a conventionally-named header such as a_fwd.h, or just as a standalone forward declaration where pointers and references to A are used.

Then, in another file somewhere, we have a class that uses PMFs for A:

using A_PMF = auto (A::*)() -> void;

class B
{
  A_PMF a_pmf;

  // other stuff...  
};

A hard-to-diagnose bug lurks here. Do you see it?

We would assume that A_PMF is the size of a pointer. Generally, multiple inheritance is rarer than single inheritance, so this is nice, and what we normally expect from MSVC.

However, the size of A_PMF — and therefore the size of B — differs depending on whether A‘s class definition is known, or A is simply forward-declared!

If A is known, the compiler knows A is using single inheritance, and therefore A_PMF can be the size of a pointer. This is our normal expectation.

If A is forward-declared, we can still declare A_PMF. But now the compiler doesn’t know for sure that A_PMF can be the size of a pointer. A could use multiple inheritance, so the compiler must err on the side of caution and use the implementation-defined structure for A_PMF.

This can lead to B being two different sizes in two different translation units! We could have one where a.h is included (and A is known) and one where only a_fwd.h is included. Both versions will compile without warnings, but of course, depending on what comes after a_pmf in B, the bug may not show up immediately.

When it does show up, it may be difficult to diagnose because the debugger probably has perfect knowledge of A_PMF and will claim that it’s the size of a pointer, even when the translation unit you’re looking at compiled it differently. You can run into situations where you print a value, but when you break at the print statement, what prints is not what the debugger shows. This can be rather confusing, to say the least!

Perhaps the moral is: if you’re going to use PMFs, declare them right next to the class they belong with, and beware forward declarations.

C++

Post navigation

Previous post
Next post

Related Posts

Functions are Asymmetric

10 October, 202510 October, 2025

Here are some functions: What they all have in common, structurally, is that they each return one thing. Even though they may take any number of arguments, they must each have one return value. One shall be the number, and the number shall be one. This is true of all…

Read More

Thoughts on Default Construction

16 August, 2017

What does default construction mean? Why do we write default constructors? When and why should we require them? I’ve been pondering these questions lately. One of the great things that C++ gets right is that it grants programmers the ability to create types that behave like built-in types. Many languages…

Read More

10 Non-C++ Book Recommendations for C++ Programmers

19 January, 2018

So you’ve learned enough C++ to function. You’ve read a bunch of the usual recommendations: Meyers, Stroustrup, maybe even Alexandrescu and Stepanov. You know enough to recommend Lippman et al. to newbies rather than the other “C++ Primer.” The internet has lots of C++-related book recommendations to make — for…

Read More

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

©2026 Why is a raven like a writing desk? | WordPress Theme by SuperbThemes