When to use Q_NULLPTR? - c++

I see Q_NULLPTR being used liberally in Qt source code and examples, but I have found no documentation for what it is exactly and when it should be used.
For example in this official demonstration of the new Qt SerialBus module added in the new Qt v5.6:
if (!m_canDevice->connectDevice()) {
delete m_canDevice;
m_canDevice = Q_NULLPTR;
Did this serve the purpose of nullptr prior to that being added in C++11? If so, now that we have C++11, should I be using Q_NULLPTR?
PS: I tried searching the Qt source code for the definition of the macro but failed to find it.

Q_NULLPTR is a macro, that is replaced as nullptr if compiler supports c++11 and as NULL (which is replaced as 0) if it doesn't. If you use c++11, you can write nullptr instead; use NULL if you don't.

Did this serve the purpose of nullptr prior to that being added in
C++11? If so, now that we have C++11, should I be using Q_NULLPTR?
Yes (somewhat) and No respectively.
C++ was quite lacking back in the days, so Qt had its own stuff, which later became obsolete as C++ caught up on the features.
That being said, Q_NULLPTR is (was) not functionally the same as nullptr, (as Andrei noted, if C++11 is supported it expands to nullptr) it didn't give you the type safety, just syntax "sugar". It illustrated the intent to the person reading the code, not to the compiler as nullptr does.

Actually Q_NULLPTR had only one purpose: To allow use of nullptr without loosing support for compilers which didn't have C++11/C++0x support, as a direct use of nullptr would result in errors in such setups. The downside is that there are ambiguities of its fallback to NULL (or 0 in older Qt versions) which might result in unintended runtime behavior and limit the supported use cases compared to nullptr.
In the rare case that you target non C++11 compliant compilers, use Q_NULLPTR but make sure that the code works well when C++11 features are disabled. In all other situations nullptr is the better alternative as it results in compilation errors instead of buggy runtime behavior when used with legacy compilers. Qt 5.7 and later dropped the support for compilation without C++11 so there is no need for Q_NULLPTR if you depend on those versions.
There are other features like qMove or Q_DECL_OVERRIDE that give improved semantic when used on supporting compilers without breaking compilation on older compilers.

Use Q_NULLPTR to stay compiler independent.
If you now decide to use nullptr, your code won't compile with an older c++98 compiler. If you decide to use NULL, you lose the c++11 type safety, even if available in your current compiler.
For the same reason macros like qMove(x) and the corresponding define Q_COMPILER_RVALUE_REFS exists.

Related

What conditional compilation is needed around C++ attributes?

I'm starting to add [[nodiscard]], [[noreturn]] and [[fallthrough]] to my code base, but I still worry the code might need to be used on an older C++ version.
I'm only worried about g++, clang, and Visual Studio.
To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
Were these allowed and ignored (or supported) even before C++11? (I ask not what the spec says but what the software actually did.)
#if __cplusplus >= 201703L
#define MyNamespace_NoReturnCPP17 [[noreturn]]
#else
#define MyNamespace_NoReturnCPP17
#endif
(Off subject but if I were on the C++ committee, I'd re-use the case keyword to do the same thing as switch, when followed by (, except it would in effect have an automatic break before each case label. And within the case's block (and nowhere else), fallthrough would be accepted as a keyword, that suppresses that automatic break.)
I note the C++14 spec 7.6.1.5 says behavior is "implemenation-defined" but I'm asking a more practical question about what compilers actually did. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
The C++17 spec 10.6.1.6 says "Any attribute-token that is not recognized by the implementation is ignored." That answers my question for C++17 and newer, but again my question is about earlier compilers. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
I prefer adding version checks for safety although mainstream compilers will throw a warning for unknown attributes.
gcc -Wno-ignored-attributes / -Wattributes
Clang -Wunknown-attributes
MSVC C5030
I'm not sure these warning options(and corresponding behavior) have been added since the first C++11 feature-complete version, so you'd better do some checks.
Were these allowed and ignored (or supported) even before C++11?
Since standard attributes syntax is supported starting from C++11, compilers will have trouble at the parsing stage. Demo

What's the MSVC equivalent for -fno-char8_t?

In C++20 u8 string literals are based on the char8_t type. They deliberately do not convert to char const* any more:
const char* str = u8"Hall\u00f6chen \u2603"; // no longer valid in C++20
Of course, the ultimate goal when migrating to C++20 is to entirely go with the new behaviour (in the example above: change the type of str). However, because of 3rd party libraries, this is often not possible immediately.
The proposals that introduce and "remedy" char8_t anticipate that and mention that in clang and gcc there is the -fno-char8_t flag to switch back to the old behaviour (while still being able to enjoy other C++20 features).
The 2nd proposal sets up the expectation that Microsoft will follow and add a similar flag, but I was not able to find how to set it (at least in VS 2019, Version 16.4).
So does anyone know what the MSVC equivalent for -fno-char8_t is?
Since 16.1, there is the conformance compiler flag /Zc:char8_t-. The minus tells the compiler to not use conformance mode here when using C++20. On the contrary, /Zc:char8_t can be used to enable it.

What's a quick simple bit of code to verify a given C++ compiler is reading source as C++11?

I think my compiler understands C++11, but maybe not. Instead of trying it on existing messes of source code which are buggy anyway, is there some simple "hello world" level snippet of source code I can try to compile, which if it does compile without error, proves the compiler is reading it as C++11?
Try this one,
auto f = [](){};
or write some code with rvalue reference.
Shortest thing possible:
[]{};
Is's a lambda-expression without argument list.
The Problem is that compiler usually don't support a new standard completely from the start. Meaning, they may support one c++11 feature, but not another.
However, as far as c++11 is concerned, I think VC++ is the only major compiler that doesn't fully support it, even though you may have to enable the c++11 mode manually. For g++ you e.g. have to supply the compiler flag -std=c++11 (or -std=gnu++11) - the same holds true for newer versions like c++14).

Why do streams still convert to pointers in C++11?

The canonical way to read lines from a text file is:
std::fstream fs("/tmp/myfile.txt");
std::string line;
while (std::getline(line, fs)) {
doThingsWith(line);
}
(no, it is not while (!fs.eof()) { getline(line, fs); doThingsWith(line); }!)
This works beacuse std::getline returns the stream argument by reference, and because:
in C++03, streams convert to void*, via an operator void*() const in std::basic_ios, evaluating to the null pointer value when the fail error flag is set;
see [C++03: 27.4.4] & [C++03: 27.4.4.3/1]
in C++11, streams convert to bool, via an explicit operator bool() const in std::basic_ios, evaluating to false when the fail error flag is set
see [C++11: 27.5.5.1] & [C++11: 27.5.5.4/1]
In C++03 this mechanism means the following is possible:
std::cout << std::cout;
It correctly results in some arbitrary pointer value being output to the standard out stream.
However, despite operator void*() const having been removed in C++11, this also compiles and runs for me in GCC 4.7.0 in C++11 mode.
How is this still possible in C++11? Is there some other mechanism at work that I'm unaware of? Or is it simply an implementation "oddity"?
I'm reasonably certain this is not allowed/can't happen in a conforming implementation of C++11.
The problem, of course, is that right now, most implementations are working on conforming, but aren't there completely yet. At a guess, for many vendors, this particular update is a fairly low priority. It improves error checking, but does little (or nothing) to enable new techniques, add new features, improve run-time efficiency, etc. This lets the compiler catch the error you've cited (some_stream << some_other_stream) but doesn't really make a whole lot of difference otherwise.
If I were in charge of updating a standard library for C++11, I think this would be a fairly low priority. There are other changes that are probably as easy (if not easier) to incorporate, and likely to make a much bigger difference to most programmers.
To use one of the examples you gave, if I were in charge of updating the VC++ standard library to take advantage of the compiler features added in the November CTP, my top priority would probably be to add constructors to the standard container types to accept initialization_lists. These are fairly easy to add (I'd guess one person could probably add and test them in under a week) and make quite an obvious, visible difference in what a programmer can do.
As late as GCC 4.6.2, the libstdc++ code for basic_ios is evidently still C++03-like.
I'd simply put this down to "they haven't gotten around to it yet".
By contrast, the libc++ (LLVM's stdlib implementation) trunk already uses operator bool().
This was a missed mini-feature buried in a pre-existing header. There are probably lots of missing error of omission and commission in pre-2011 components.
Really, if anyone comes up with things like this in gcc then it would do a world of good to go to Bugzilla and make a bug report. It may be a low priority bug but if you start a paper trail
I'll go out on a limb and extend this idea to all the other C++ compilers: clang, Visual Studio,etc.
This will make C++ a better place.
P.S. I entered a bug in Bugzilla.

How to define nullptr for supporting both C++03 and C++11? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“Backporting” nullptr to C++-pre-C++0x programs
How to define nullptr for supporting both C++03 and C++11?
Does below code is compiled with both C++03 and C++11 compiles without change the meaning of nullptr in C++11 compiler?
#include <cstddef>
#if !defined(nullptr)
#define nullptr NULL
#endif
In C++11, nullptr is of type nullptr_t. One of its big advantages compared to NULL (or to 0 would say Bjarne since he does not like macros) is that between these two functions:
void foo(char*);
void foo(int);
foo(nullptr) will call the char* overload but foo(NULL) will call the int overload. So your solution may work in most of the cases, but you may have errors with functions overload.
AFAIK you cannot automate from within the code the detection of nullptr support.
In practice you can read that as “impossible”, it’s a pretty strong “AFAIK”.
The thing to do is therefore to use compiler-specific code and/or build command. For example, in each relevant source add a
#include <cpp/nullptr.h>
and in the build command adjust the include path so that for compiler with nullptr support, this picks up an empty header, while for an old compiler that lacks nullptr, it picks up a header that defines it à la Meyers (say).
And then test very thoroughly!
I call the general concept of having multiple versions of a header, with just one selected by the build command, a virtual header. It is possible to build a lot of machinery around that, including conventions that only make sense in a more general case. Happily it’s not necessary for this particular case, but perhaps worth to be aware of.
Summing up: making C++ source code do things magically is not the way to go here. Adding a bit of help at the build level seems about right. :-)