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...
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.
When working with object references in JNI, I can use NewLocalRef to (as the name implies) get a new local reference to the same object.
This is useful when implementing a wrapper in C++. The copy-constructor can invoke NewLocalRef and both instances of the class' destructors can simply use DeleteLocalRef on their own local reference.
I'm also wrapping Java classes using a similar pattern, but calling NewLocalRef with a jclass seems to result in extremely strange (possibly undefined) behaviour.
Is there a way of achieving this using JNI built in functionality, or do I need to write my own reference counter?
While reading "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" I came across the following:
Note that using a reference or auto_ptr member is almost always wrong.
However, the text doesn't elaborate on why this should be wrong. So what is so wrong about having a class with reference members?
I think the text is telling you to avoid embedding in a class anything whose existence is out of the control of that class. References and auto pointers may refer to already deleted objects.
One problem might be that references are immutable, once set they can't be changed.. Another problem might be dangling references, where you have a reference to now destroyed object.
A reference member can never be changed, rendering the class non-assignable. The same goes for members of const object type. Also, the best practice is to set any invalidated reference to nullptr, but that cannot be applied.
Simply use a pointer instead. There is also std::reference_wrapper for the cases where a bare pointer really won't do.
auto_ptr is long obsolete and deprecated, so that simply shouldn't come up. It had wonky copy semantics.
I don't really understand the difference between a shared_ptr and the new handle notation (^) in C++/CX. From what I've read they seem to do the same thing regarding reference counting and memory management. What am I missing?
std::shared_ptr<Type>
//vs
Type^
Solely considering lifetime management, these are the same: a shared_ptr<T> holds a strong (owning) reference to a T object; a T^ does the same. make_shared<T> is roughly equivalent to ref new T in C++/CX.
If everywhere you see a T^ you think shared_ptr<T> or ComPtr<T> or CComPtr<T>, then that's okay--the lifetime management is roughly the same.
How lifetime management works under the hood is different, though: every T type for which T^ is well-formed is a Windows Runtime reference type that implements the IUnknown interface, so the T object is internally reference counted(*). shared_ptr<T> supports arbitrary types and uses external reference counting (i.e., it allocates its own reference counting mechanism to control the lifetime of the object).
For weak references, shared_ptr<T> has weak_ptr<T>, and T^ has WeakReference. WeakReference is not strongly-typed, but you can easily write a strongly-typed reference wrapper around it. Otherwise, weak references work as you would expect them to. Support for weak references is optional: not all reference types support weak references, but most do.
(*) There is one exception: Platform::String^, which is not a Windows Runtime reference type, but is handled specially for a variety of reasons. You can think of it as being the same as any other T^ with respect to lifetime management, though.
So, why do Windows Runtime types wear hats in C++/CX? Why isn't a library solution like shared_ptr<T> or ComPtr<T> used?
It's because you never really have a pointer (or a hat) to a concrete runtime type: you can only interact with an object via a pointer to one of the interfaces that its type implements. Windows Runtime also does not support interface or class inheritance: every interface must derive directly from IInspectable, and class inheritance is emulated through the use of COM aggregation.
In short, there's no library solution that would result in natural looking C++ code with static type safety. Function calls, derived-to-base conversions, and interface conversions usually require a call to QueryInterface to get the right interface pointer.
You can do this with a library solution (see, for example, the WRL library, or pretty much any COM code), but you can't support C++ language features like implicit conversions or dynamic_cast. Without the hats, you're stuck dealing solely with interface pointers and having to call QueryInterface yourself.
(If you're interested in the rationale behind why the C++/CX language extension were developed and how the C++/CLI syntax ended up being selected for reuse, I'd recommend Jim Springfield's post on this blog from last year, "Inside the C++/CX Design". Also of note is episode 3 of GoingNative, in which Marian Luparu discusses C++/CX.)
As far as I can tell, the latter lacks support for weak references and custom deallocation functions.
Note that the former, being more general, accepts any type (in principle), and for safety and cleanliness calls for the use of the helper function make_shared. The latter is supported at a language level. That means code like this is safe in C++/CX:
some_function(ref new foo(), ref new bar());
While in C++, you need to do this:
// bad: if foo is allocated but bar's allocation throws, you leak!
some_function(new foo(), new bar());
// good: both never make it anywhere but into a shared_ptr, no leaks
some_function(make_shared<foo>(), make_shared<bar>());
Other than that, sure, they implement the same concept. If you're in C++/CX land, use the latter syntax for simplicity and uniformity; if you're trying to stick to standard C++, or are wrapping an existing resource management scheme into a reference-counted scheme, then you'll want the former.
My C++ knowledge is somewhat piecemeal. I was reworking some code at work. I changed a function to return a reference to a type. Inside, I look up an object based on an identifier passed in, then return a reference to the object if found. Of course I ran into the issue of what to return if I don't find the object, and in looking around the web, many people claim that returning a "null reference" in C++ is impossible. Based on this advice, I tried the trick of returning a success/fail boolean, and making the object reference an out parameter. However, I ran into the roadblock of needing to initialize the references I would pass as actual parameters, and of course there is no way to do this. I retreated to the usual approach of just returning a pointer.
I asked a colleague about it. He uses the following trick quite often, which is accepted by both a recent version of the Sun compiler and by gcc:
MyType& someFunc(int id)
{
// successful case here:
// ...
// fail case:
return *static_cast<MyType*>(0);
}
// Use:
...
MyType& mt = somefunc(myIdNum);
if (&mt) // test for "null reference"
{
// whatever
}
...
I have been maintaining this code base for a while, but I find that I don't have as much time to look up the small details about the language as I would like. I've been digging through my reference book but the answer to this one eludes me.
Now, I had a C++ course a few years ago, and therein we emphasized that in C++ everything is types, so I try to keep that in mind when thinking things through. Deconstructing the expression: "static_cast<MyType>(0);", it indeed seems to me that we take a literal zero, cast it to a pointer to MyType (which makes it a null pointer), and then apply the dereferencing operator in the context of assigning to a reference type (the return type), which should give me a reference to the same object pointed to by the pointer. This sure looks like returning a null reference to me.
Any advice in explaining why this works (or why it shouldn't) would be greatly appreciated.
Thanks,
Chuck
This code doesn't work, though it may appear to work. This line dereferences a null pointer:
return *static_cast<MyType*>(0);
The zero, cast to a pointer type, results in a null pointer; this null pointer is then dereferenced using the unary-*.
Dereferencing a null pointer results in undefined behavior, so your program may do anything. In the example you describe, you get a "null reference" (or, it appears you get a null reference), but it would also be reasonable for your program to crash or for anything else to happen.
I agree with other posters that the behaviour of your example is undefined and really shouldn't be used. I offer some alternatives here. Each of them has pros and cons
If the object can't be found, throw an exception which is caught in the calling layer.
Create a globally accessible instance of MyType which is a simple shell object (i.e. static const MyType BAD_MYTYPE) and can be used to represent a bad object.
If it's likely that the object will not be found often then maybe pass the object in by reference as a parameter and return a bool or other error code indicating success / failure. If it can't find the object, you just don't assign it in the function.
Use pointers instead and check for 0 on return.
Use Boost smart pointers which allow for the validity of the returned object to be checked.
My personal preference would be for one of the first three.
That is undefined behavior. Because it is undefined behavior, it may "work" on your current compiler, but it could break if you ever upgrade/change your compiler.
From the C++03 spec:
8.3.2/4 ... A reference shall be initialized to refer to a valid object or function. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.
If you are married to that return-a-reference interface, then the Right Thing®
would be to throw an exception if you can't find an object for the given ID. At least that way your poor user can trap the condition with a catch.
If you go dereferencing a null pointer on them, they have no defined way to handle the error.
The line return *static_cast<MyType*>(0); is dereferencing the null pointer which causes undefined behaviour.
Well, you said it yourself in the title of your question. The code appears to work with a null reference.
When people say null references do not exist in C++, it does not mean that the compiler will generate an error message if you try to create one. As you've found out, there's nothing to stop you from creating a reference from a null pointer.
It simply means that the C++ standard does not specify what should happen if you do it. Null references are not possible because the C++ standard says that references must not be created from null pointers. (but doesn't say anything about generating a compile error if you try to do it.)
It is undefined behavior. In practice, because references are typically implemented as pointers, it usually seems to work if you try to create a reference from a null pointer. But there's no guarantee that it'll work. Or that it'll keep working tomorrow. It's not possible in C++ because if you do it, the behavior specified by C++ no longer applies. Your program might do anything
This might all sound a bit hypothetical, because hey, it seems to work just fine. But keep in mind that just because it works, and it makes sense that it works, when naively compiled, it may break when the compiler tries to apply some optimization or other. When the compiler sees a reference, it is guaranteed by the language rules that it is not null. So what happens if the compiler uses this assumption to speed up the code, and you go behind its back creating a "null reference"?
As others have already said, the code unfortunately only appears to work... however, more fundamentally, you are breaking a contract here.
In C++, a reference is meant to be an alias for an object. Based on the signature of your function I would never expect to be passed a 'NULL' reference, and I would certainly NOT test it before using it. As James McNellis said, creating a NULL reference is undefined behavior, however in most case this behavior only creeps in when you actually try to use it, and you are now exposing the users of your methods to nasty / tricky to nail down bugs.
I won't go any further on that issue, just points you toward Herb Sutter's pick on the issue.
Now for the solution to your problem.
The evident solution is of course a plain pointer. People expect a pointer to be possibly null, so they will test it when it's returned to them (and if they don't it's their damn fault for being lazy).
There are other alternatives, but they mainly boil down to having a special value indicating your failure and there is not much point using complicated designs just for the sake of it...
The last alternative is the use of exceptions here, however I am myself partial to the advice. Exceptions are meant for exceptional situations you see, and for a find/search feature it really depends on the expected result:
if you are implementing some internal factory where you register modules and then call them back later on, then not being able to retrieve one module would indicate an error in the program and as such being reported by an exception is fine
if you are implementing a search engine for a database of yours, thus dealing with user input, then not finding a result matching the input criteria is quite likely to occur, and thus I would not use exceptions in this circumstance, for it's not a programming error but a perfectly normal course
Note: other ways include
Boost.Optional, though I find it clumsy to wrap a reference with it
A shared pointer or weak pointer, to control/monitor the object lifetime in case it may be deleted while you still use it... monitoring does not work by itself in Multi-Threaded environment though
A sentinel value (usually declared static const), but it only works if your object has a meaningful "bad" or "null" value. It's certainly not the approach I would recommend since once again you give an object but it blows up in the users hand if they do anything with it
As others have mentioned, your code is erroneous since it dereferences a null pointer.
Secondly, you are using the reference return type incorrectly, returning a reference in your example is usually not good in C/C++ since it violates the memory management model of the language where all objects are referenced to by pointers to a memory address. If you rewrite C/C++ code that was written using pointers into code that uses references you will end up with these problems. The code using pointers could return a NULL pointer without causing problems, but when returning a reference you must return something that can be cast into a 0 or false statement.
Most important of all is the pattern where your erroneous code only gets executed in the case of an exception, in this example your "fail case". Incorrect error handling, error logging with bugs etc are the most disastreous bugs in computer systems since they never show up in the happy case but always causes a system breakdown when something doesnt follow the normal flow.
The only way to ensure that your code is correct is to have testcases with 100% coverage, that means also testing the error handling, which in your example probably would cause a segmentation fault on your program.