6

After adding the comment "// not null" to a raw pointer for the Nth time I wondered once again whatever happened to the not_null template.

The C++ core guidelines were created quite some time ago now and a few things have made into into the standard including for example std::span (some like string_view and std::array originated before the core guidelines themselves but are sometimes conflated). Given its relative simplicity why hasn't not_null (or anything similar) made it into the standard yet?

I scan the ISO mailings regularly (but perhaps not thoroughly) and I am not even aware of a proposal for it.


Possibly answering my own question. I do not recall coming across any cases where it would have prevented a bug in code I've worked on as we try not to write code that way.

The guidelines themselves are quite popular, making it into clang-tidy and sonar for example. The support libraries seem a little less popular.

For example boost has been available as a package on Linux from near the start. I am not aware of any implementation of GSL that is. Though, I presume it is bundled with Visual C++ on windows.


Since people have asked in the comments.

Myself I would use it to document intent. A construct like not_null<> potentially has semantic value which a comment does not. Enforcing it is secondary though I can see its place. This would preferably be done with zero overhead (perhaps at compile time only for a limited number of cases).

I was thinking mainly about the case of a raw pointer member variable. I had forgotten about the case of passing a pointer to a function for which I always use a reference to mean not-null and also to mean "I am not taking ownership".

Likewise (for class members) we could also document ownership owned<> not_owned<>.

I suppose there is also whether the associated object is allowed to be changed. This might be too high level though. You could use references members instead of pointers to document this. I avoid reference members myself because I almost always want copyable and assignable types. However, see for example Should I prefer pointers or references in member data? for some discussion of this.

Another dimension is whether another entity can modify a variable. "const" says I promise not to modify it. In multi-threaded code we would like to say almost the opposite. That is "other code promises not to modify it while we are using it" (without an explicit lock) but this is way off topic...

Bruce Adams
  • 4,953
  • 4
  • 48
  • 111
  • Related questions I dare not ask: * Why wasn't the [GSL](https://github.com/Microsoft/GSL/) a good fit for boost? (opinion based?) * What other features from GSL have made it or are likely to make it into the standard? (moving target) – Bruce Adams May 06 '22 at 16:35
  • 3
    I'm trying to think of a use-case for that. I feel that I'd prefer to spell `not_null` with `int&` instead. – Yksisarvinen May 06 '22 at 16:37
  • Question is, why there is a raw pointer that cannot be null... `std::reference_wrapper`. Traditionally presence of pointer suggests it can be stale or null. – Swift - Friday Pie May 06 '22 at 16:37
  • You could make a `valid_ptr` wrapper that disallows `nullptr` (throws exception? std::terminate()?). Wouldn't detect uninitialized pointers or dangling pointers, though. You could use references `Foo&` that disallow null, but puts the burden on the callsite. – Eljay May 06 '22 at 16:38
  • @BruceAdams: "*std::string_view, std::span, std::array*" `string_view` and `array` were added to C++ *before* the C++ core guidelines even existed. Only `span` originated from there. – Nicol Bolas May 06 '22 at 16:38
  • I think GSL is in the same category as Abseil or Folly. The GSL charter is orthogonal to the Boost charter. – Eljay May 06 '22 at 16:41
  • Need more context. What situations do you "need" RAW pointer that can't be null. Is there not some other construct that would model your use case better? You adding a comment is **not** a good solution (there is no enforcement of a comment by a compiler) and if I was reviewing your code I would ask you to remove that (or added more context that is a terrible comment by itself). – Martin York May 06 '22 at 16:44
  • 1
    @Yksisarvinen: "*I'm trying to think of a use-case for that. I feel that I'd prefer to spell not_null with int& instead.*" That doesn't work for `not_null>`. The main point of `not_null` is that it works for smart pointers or any nullable type (that is not move-only). – Nicol Bolas May 06 '22 at 16:44
  • `// not null` seems borked to start with. A reference would solve that, wouldn't it? Is the core guide promoting pointers? – Ted Lyngmo May 06 '22 at 16:44
  • 1
    Reference wouldn't work if the pointer could be changed. – user4581301 May 06 '22 at 16:46
  • @user4581301 Take by ref, store as pointer – Ted Lyngmo May 06 '22 at 16:46
  • @Eljay Abseil and Folly are company specific offerings though (open sourcing what they found useful internally). The GSL was much more language centric. Likewise boost is more aimed at extending the standard libraries. – Bruce Adams May 06 '22 at 16:46
  • @user4581301 depends on context. A reference parameter (rather than a pointer) is changed each time you call it. – Martin York May 06 '22 at 16:47
  • 1
    Interesting that no people (that commented so far) have ever programmed to a coding standard the requires output parameters to be passed by non-owning raw pointer (which *has* benefits). So yes, comments and asserts exists, but a standard utility is much better vocabulary. – StoryTeller - Unslander Monica May 06 '22 at 16:47
  • @TedLyngmo Take by ref, store as pointer is exactly the scenario where I find myself adding "// not null" comments to a class's members. – Bruce Adams May 06 '22 at 16:48
  • GSL is from Microsoft, because Herb Sutter works for Microsoft. (Even if intended, as it is, to be language centric.) May have been as odds with some of the Boost licensing constraints. Purely speculative. You can use both GSL and Boost. – Eljay May 06 '22 at 16:49
  • @BruceAdams Aha ... But, why is the comment even needed then? – Ted Lyngmo May 06 '22 at 16:49
  • 1
    @MartinYork: "*I would even consider out parameters an anti pattern and expect the function to return the obejct.*" There are still plenty of cases where you're expected to have a legitimate object. And returning multiple values in a `tuple` or whatever can be cumbersome and even inhibit elision. – Nicol Bolas May 06 '22 at 16:51
  • That's the fun thing about C++: Context is everything. – user4581301 May 06 '22 at 16:51
  • @StoryTeller-UnslanderMonica Is this what the OP is asking about? Can't tell, maybe they can clarify. But I can think of alternative solutions to that use case that are better suited. – Martin York May 06 '22 at 16:51
  • @StoryTeller-UnslanderMonica "have ever" isn't the same as seeing it as over and done with :) – Ted Lyngmo May 06 '22 at 16:51
  • 1
    @MartinYork: "*Can't tell may he can clarify.*" How would this change the question or the answer? If you want to argue that `not_null` is a bad idea, you can say so in an answer. – Nicol Bolas May 06 '22 at 16:52
  • wait, is this about comments only? And i get myself fuming over the codebase where at some point of upgrade to Qt 4 someone commented about 12 000 lines of code with `/// 4` – Swift - Friday Pie May 06 '22 at 16:52
  • @TedLyngmo because the comment is intended, like not_null<>, to document that intention. Someone could try to alter the interface to receive or expose a pointer. They would likely fail my code review in the process though. – Bruce Adams May 06 '22 at 16:52
  • @MartinYork - Does it matter if that's what the OP refers to? There are comments proclaiming a case for it cannot be envisioned at all. And while I'm sure some cases may work with other tools, I can also think of cases where output parameters will stand out. – StoryTeller - Unslander Monica May 06 '22 at 16:53
  • @BruceAdams Ok, it starts to make sense. The intent should be so clear that violating it should result in a compilation error. ... and C++ lacks that with regards to this? – Ted Lyngmo May 06 '22 at 16:55
  • 1
    @NicolBolas I want to know the context in which the OP thinks they need it before I argue for or against not_null. Side note: I can't answer the question "What happened to not_null" because I don't know. – Martin York May 06 '22 at 16:55

1 Answers1

15

There is one big technical issue that is likely unsolvable which makes standardizing not_null a problem: it cannot work with move-only smart pointers.

The most important use case for not_null is with smart pointers (for raw pointers a reference usually is adequate, but even then, there are times when a reference won't work). not_null<shared_ptr<T>> is a useful thing that says something important about the API that consumes such an object.

But not_null<unique_ptr<T>> doesn't work. It cannot work. The reason being that moving from a unique pointer leaves the old object null. Which is exactly what not_null is expected to prevent. Therefore, not_null<T> always forces a copy on its contained T. Which... you can't do with a unique_ptr, because that's the whole point of the type.

Being able to say that the unqiue_ptr consumed by an API is not null is good and useful. But you can't actually do that with not_null, which puts a hole in its utility.

So long as move-only smart pointers can't work with not_null, standardizing the class becomes problematic.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • But this question is about RAW pointers. But good answer on what happened to not_null itself. – Martin York May 06 '22 at 16:59
  • 1
    @MartinYork Is it? The title and the bosy both ask *Given its relative simplicity why hasn't not_null (or anything similar) made it into the standard yet?* which this answer very well. – NathanOliver May 06 '22 at 17:01
  • @NathanOliver Yep that's true. I got so wrapped up in why the OP was asking I overlooked the actual question. – Martin York May 06 '22 at 17:05
  • This presumes that not_null for raw pointers is not useful in and of itself. Why does it need to work for all conceivable cases? Couldn't we make not_null> result in a static assertion failure? – Bruce Adams May 06 '22 at 17:07
  • @BruceAdams: "*This presumes that not_null for raw pointers is not useful in and of itself.*" You mean, besides the part where I acknowledged that there were useful cases there too? "*Why does it need to work for all conceivable cases?*" Because if it's not universal, it's not doing its job. The whole point is to remove ambiguity. If it leaves ambiguity, then you have to fall back on other methods. So you may as well use the thing that always works. – Nicol Bolas May 06 '22 at 17:10
  • I may update the question with the why, which is. I hesitated before rushing to download GSL or roll my own. I'm happier to do that if I'm writing a polyfill for a future standard but the standard might have decided on a different name or approach (e.g. maybe owned<> is more appropriate). – Bruce Adams May 06 '22 at 17:11
  • @NicolBolas I'm not sure I follow why it would leave ambiguity? So I can't use it with some pointer types including granted one of the most important ones but I can with many others. Covering some use cases is surely better than covering none? This does of course have to be weighed against the learning burden. Perhaps this is a feature intended to be friendly to new learners rather than experts only. – Bruce Adams May 06 '22 at 17:24