Why gsl::not_null ensures ptr is not null on get()? - c++

In the Microsoft implementation of guidelines support library I see the following piece of code:
template<class T>
class not_null {
...
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr explicit not_null(U&& u) : ptr_(std::forward<U>(u)) {
Expects(ptr_ != nullptr);
}
...
constexpr T get() const {
Ensures(ptr_);
return ptr_;
}
...
T ptr_;
}
All the constructors of gsl::not_null which take possibly pointers check these pointers are not null, but we still check stored value of pointer (ptr_) against null on each dereference. Why do we have this check, given that in C++ we typically don't pay for what we don't need?
UP: Ensures is implemented as follows (with default flags):
#define GSL_LIKELY(x) (!!(x))
...
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
...
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)

The comments are already giving the idea why removing null check from not_null::get() is not desirable. The main problem is that the change allows dereferencing a smart pointer after move.
For examples, see the following discussion on a PR that enables usage of not_null<unique_ptr> and how the change is incompatible with removing the null check from not_null::get()
https://github.com/Microsoft/GSL/pull/675
As for performance concerns, compiler optimizer should be able to remove many of the null checks, but not all, of course. If some checks are not removed but seem to be removable, we should fix compiler optimizations.

Related

How to implement a function that safely cast any larger type to a smaller type in C++ using templates?

I'm trying to write a function that checks if the variable being cast can fit in the destination type, and assert() if not. Right now this is what I came up with. I didn't test it yet. I would like to make the template figure out the type of the varible being passed automatically, with something like typeid, although I don't really know what typeid really is. Is that possible? Also, I don't know much about templates.
template<typename from_T, typename to_T>
static inline to_T safe_cast(from_T variable)
{
assert(variable >= std::numeric_limits<to_T>::min());
assert(variable <= std::numeric_limits<to_T>::max());
return static_cast<to_T>(variable);
}
Well, if that is actually some function that already does this that I don't know of I will be glad to hear.
C++ Core Guidelines already has a gsl::narrow
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
You can see the Microsoft implementation here
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U>
constexpr T narrow(U u) noexcept(false)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
const T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
{
throw narrowing_error{};
}
return t;
}
You can see the explanation of the implementation on this SO post (it's for an older version of the implementation, but nothing substantially changed, so the answer still applies).

Implicitly cast parameter to bool

Premise:
I am trying to make a Define scope that is not implemented using a macro because of the potential issues with macros. Here is my initial attempt
//version for if not defined
bool Defined()
{
return false
}
//version for if defined
bool Defined(bool anything)
{
return true;
}
And an example use case
if(Defined(_DEBUG))
{
Stuff...
}
which would replace
#ifdef _DEBUG
Stuff...
#endif
or
#define Defined() false
#define Defined(Anything) true
Benefits:
syntax is cleaner, it is scoped,
This code is not conditional, so the compiler will be able to easily optimize code sections out.
Issues
There are a few issues with this procedure, the first is the reason for this post.
Question:
You can't pass in anything that is not implicitly cast-able to a bool. Is there a way to implicitly cast any object, number, pointer, etc to a bool? I don't believe there is, but I wanted to make sure, before I continued.
You can use a generic template:
template<class T>
bool Defined(T &&) { return true; }

Is it possible to ignore [[nodiscard]] in a special case?

C++17 has a new attribute, [[nodiscard]].
Suppose, that I have a Result struct, which has this attribute:
struct [[nodiscard]] Result {
};
Now, if I call a function which returns Result, I got a warning if I don't check the returned Result:
Result someFunction();
int main() {
someFunction(); // warning here, as I don't check someFunction's return value
}
This program generates:
warning: ignoring return value of function declared with 'nodiscard'
attribute [-Wunused-result]
So far, so good. Now suppose, that I have a special function, for which I still want to return Result, but I don't want this warning generated, if the check is omitted:
Result someNonCriticalFunction();
int main() {
someNonCriticalFunction(); // I don't want to generate a warning here
}
It is because, someNonCriticalFunction() does something non-critical (for example, something like printf - I bet that no-one checks printf's return value all the time); most cases, I don't care if it fails. But I still want it to return Result, as in some rare cases, I do need its Result.
Is it possible to do this somehow?
Possible solutions which I don't like:
I would not like calling it as (void)someNonCriticalFunction(), because this function is called a lot of times, it is awkward
creating a wrapper around someNonCriticalFunction(), which calls (void)someNonCriticalFunction(): I don't want to have a differently named function just because of this
removing [[nodiscard]] from Result, and add it to every function which returns Result
Why not make use of std::ignore from the <tuple> header—that would make the discard explicit:
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
std::ignore = MyFunction();
return 0;
}
Compiler explorer of this code snippet: https://godbolt.org/z/eGPsjajz8
CPP Reference for std::ignore: https://en.cppreference.com/w/cpp/utility/tuple/ignore
I recommend the option you ruled out:
"removing [[nodiscard]] from Result, and add it to every function which returns Result."
But since you don't seem happy with it, here's another solution, using bog-standard inheritance:
struct [[nodiscard]] Result {
};
struct DiscardableResult: public Result {
};
For the functions where you can discard the result, use DiscardableResult as return type:
Result func1();
DiscardableResult func2();
func1(); // will warn
func2(); // will not warn
They say that every problem in computer science can be solved by adding another layer of indirection:
template <bool nodiscard=true>
struct Result;
template <>
struct Result<false> {
// the actual implementation
};
template <>
struct [[nodiscard]] Result<true>
: Result<false>
{
using Result<false>::Result;
};
This is effectively making Result conditionally [[nodiscard]], which allows:
Result<true> someFunction();
Result<false> someNonCriticalFunction();
int main() {
someFunction(); // warning here
someNonCriticalFunction(); // no warning here
}
Although really, this is identical to:
removing [[nodiscard]] from Result, and add it to every function which returns Result
which gets my vote to begin with.
You can suppress the warning with another C++17 attribute, namely [[maybe_unused]]
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
[[maybe_unused]] auto v = MyFunction();
return 0;
}
This way you also avoid the confusing dependency to std::tuple which comes with std::ignore, even CppCoreGuidelines is openly recommending to use std::ignore for ignoring [[nodiscard]] values:
Never cast to (void) to ignore a [[nodiscard]]return value. If you
deliberately want to discard such a result, first think hard about
whether that is really a good idea (there is usually a good reason the
author of the function or of the return type used [[nodiscard]] in the
first place). If you still think it's appropriate and your code
reviewer agrees, use std::ignore = to turn off the warning which is
simple, portable, and easy to grep.
Looking at C++ reference, officially std::ignore is only specified to be used in std::tie when unpacking tuples.
While the behavior of std::ignore outside of std::tie is not formally
specified, some code guides recommend using std::ignore to avoid
warnings from unused return values of [[nodiscard]] functions.
cast the result to a (void *).
int main()
{
(void *)someFunction(); //Warning will be gone.
}
This way you "used" your result as far as the compiler is concerned. Great for when you are using a library where nodiscard has been used and you really don't care to know the result.

Is there a difference between `static_cast<bool>(x)` and `x != 0.0`?

The Setup
I'm working with the API for an application called MotionBuilder. In order to access a MotionBuilder property's value, you read it into a double variable, regardless of what sort of data type it actually represents.
Here's a utility function I wrote to evaluate the value of a scalar property:
template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
double data = 0.0;
prop.GetData(&data, sizeof(data), evaluateInfo);
return static_cast<DataT>(data);
}
This way, I can write GetScalar<float>(camera.Roll, evaluateInfo) or GetScalar<bool>(camera.Visibility, evaluateInfo) instead of having a multiple-line mess of uninitialized buffers and casts littering my code.
I'm compiling in Visual Studio with /W4 and addressing all warnings as they come up. When I use GetScalar<bool>, the compiler produces a C4800 warning:
'double' : forcing value to bool 'true' or 'false' (performance warning)
When the compiler creates GetScalar<bool>, it winds up with a static_cast from double to bool, which it apparently doesn't like. Since my original aim was to handle multiple types (bool, float, double, etc) with a single template function, I can't just add in the usual != 0.0.
In order to address this warning, I have two options.
Option 1
I can suppress the warning directly with pragmas, since the cast is doing exactly what I wanted it to do:
template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
double data = 0.0;
prop.GetData(&data, sizeof(data), evaluateInfo);
#pragma warning (push)
#pragma warning (disable: 4800) // Don't complain about casting to bool
return static_cast<DataT>(data);
#pragma warning (pop)
}
Option 2
I can add a specialization of GetScalar to handle the bool case:
template <>
inline bool GetScalar<bool>(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
double data = 0.0;
prop.GetData(&data, sizeof(data), evaluateInfo);
return data != 0.0;
}
The Question
I would think that for some double x, static_cast<bool>(x) is exactly equivalent to x != 0.0. In fact, a simple test compiled in release mode gives me the same assembly output in both cases. Why, then, does C4800 call itself a "performance warning?" Are the two options outlined above functionally identical? If it comes down to a matter of style, after putting on your best pedant hat, which option do you prefer?
It's a warning, and it's telling you that there might be a performance issue for this conversion. Since you want to do the conversion, just do it. Don't waste time writing elaborate workarounds for warnings that aren't telling you anything useful.
I do think that for the case of bool, comparison to 0 is more readable than a cast. I would also question whether it semantically makes sense to have a function which can be specialised for numeric types and bool with the same implementation, even if that happens to work here.
Generally. In your particular case, I think having a uniform template is fine, and if it avoids code duplication, that’s an advantage. If anything, I would probably only create a function specialisation for the cast-to-DataT part, not the whole function:
template <typename T>
T convertTo(double d) { return static_cast<T>(d); }
template <>
double convertTo<bool>(double d) { return d != 0.0; }
template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
double data = 0.0;
prop.GetData(&data, sizeof(data), evaluateInfo);
return convertTo<DataT>(data);
}
Or you could selectively disable the warning, but if you do so, explain in a comment why this is necessary here.
I'm not sure what the best solution for your particular setup is (I think static-casting to bool is perfectly fine), but a generic way to handle branching is to create separate traits for each individual operation. In your case, that's "convert_to_bool":
template <typename Out>
struct converter
{
static Out from_double(double x)
{
return static_cast<Out>(x);
}
};
template <>
struct converter<bool>
{
static bool from_double(double x)
{
return x != 0;
}
};
Now you can use:
return converter<DataT>::from_double(data);
This way you can handle every situation that crops up in your main template and requires special treatment for certain types without ever having to branch your main template.
This is one of the rare cases where I would use the functional-notation version of the cast, rather than static_cast. The compiler will not give any warnings, because this form of cast effectively tells it that you 'know what you're doing'.
template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
double data = 0.0;
prop.GetData(&data, sizeof(data), evaluateInfo);
return DataT(data);
}
In general, beware of using this type of cast in C++, because it can suppress meaningful warnings. I would only use it to suppress warnings when casting between arithmetic types (e.g. int, double, enum), when I don't care about handling overflow.

implementation safe nullptr

I'd like to keep my code compilable both on legacy C++ (C++ code using "NULL") and new C++11 standard (C++ code using "nullptr")
I'm using GCC, but planning to recompile the whole codebase also for VS when I'll finish most important things.
Should I expect both GCC and VS will do something like
#define NULL nullptr
Or Is better I'll do that myself (using of course a different name, where MY_LIB will be replaced by my library suffix)?
#ifndef nullptr
#define MY_LIB_NULL NULL
#else
#define MY_LIB_NULL nullptr
#endif
What I want to achieve is code that compiles regardless of wich C++11 features have been implemented or not (and since i'm not using templates, there are very few of them).
For example the keywords "override" and "final" are already done.
MY_LIB_OVERRIDE //macro, defines to "override" if c++11 is present.
MY_LIB_FINAL //macro, defines to "final" if c++11 is present.
I'm asking the question because I know the "nullptr" question is a bit strange, so maybe just doing the same I already did for override and final, is wrong. Needs opinions about that. Any help is wellcome.
You could probably create a "false" my_nullptr of type my_nullptr_t the following way:
const class my_nullptr_t
{
public:
/* Return 0 for any class pointer */
template<typename T>
operator T*() const
{
return 0;
}
/* Return 0 for any member pointer */
template<typename T, typename U>
operator T U::*() const
{
return 0;
}
/* Safe boolean conversion */
operator void*() const
{
return 0;
}
private:
/* Not allowed to get the address */
void operator&() const;
} my_nullptr = {};
This works with C++03 and C++11 and should always be safe, whichever C++11 features are implemented. That solution was actually already discussed in this topic that proposed a version of nullptr_t based on the Official proposal.
NULL is a macro that expands to a null pointer constant. It still works just like it used to. Code that has to work with non-C++11 compilers should use NULL.
I think following will works:
#include <cstddef>
#ifndef MY_LIB_NULL
#ifndef NULL //check for NULL
#define MY_LIB_NULL nullptr
#else
#define MY_LIB_NULL NULL ///use NULL if present
#endif
#endif
basically I check for "NULL". wich is a macro and can be checked, until the compiler is shipped with that macro (likely to be), than it's valid using the macro, when compiler will only provides "nullptr" and no longer have NULL then nullptr is used (maybe in a far future, but seems we can happily continue to use NULL!)
I think that's safer than redefining "nullptr" (like most people trying to do)