Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 16.  Keywords


16.5. unique

We all know that any function declared inline is guaranteed to only have a single instantiation, don't we? In fact, that guarantee is about as strong as the one you get from a real estate agent that "compact and bijou" won't translate in actuality to "pokey and cramped." What's the problem?

Within a single source file or, rather, a single compilation unit, the compiler handles the business of ensuring that a function that is called in multiple places is only given one instance. That's the basis of procedural programming, at which both C and C++ excel. Multiple definitions within a single source file are a language error, so the question of how to fold them into one does not arise.

Within a link unit, a given inline function notionally has only one instance, and the C++ language mandates that the compiler and linker should cooperate to ensure that this is true: "An inline function with external linkage shall have the same address in all translation units" (C++-98: 7.1.2; 4).

In other words, within any link unit (see section 9.2), there is only one instance. However, looking a little deeper, we see that the standard admits the force of reality, and actually only requires that an inline function "shall have the same address in all translation units." What this recognizes is that you could, for example, with the preprocessor, mess with the definition of an inline function, and produce different definitions of the "same" function, thereby violating the one definition rule. Hence the standard only requires that taking the address across compilation units reports the same value. It's a kind of "as much as we can do" measure, and you should be aware of it.

Once we step outside of link units, it is clearly impossible to mandate that only one instance of one function can exist in a given process. Even if the language provided lots of support, and we could ensure that every dynamic unit within a process did not contain any function that was defined in any other module (something that is impossible in practice), we would lose out at the operating system level. Where two or more processes, with arbitrarily large amounts of time (and versions) between their production, could share an operating system module, it would be impossible to ensure that neither contained a function that was already defined within any of their shared system modules. This is because these shared modules could have evolved during the span of the creation times of the processes and their specific subcomponents.

We saw some of the good and bad points of all this when we looked at shared contexts in Chapter 9. What we can say for now is that where it is not impossible/impractical, and where malicious action is not expected/tolerated, the inline specifier serves well as our unique keyword.

See section 12.1 for a discussion of other uses of inline.


      Previous section   Next section