11
\$\begingroup\$

I tried to write a nullptr_t class based on the official proposal to be used in C++03 only. The only differences with the proposal are that we can compare two nullptr_t instances and that it is convertible to bool via an overload to void* to avoid unwanted behaviour such as int a = nullptr; for example. Here is the class:

const class 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;
 }
 // Used for bool conversion
 operator void*() const
 {
 return 0;
 }
 // Comparisons with nullptr
 bool operator==(const nullptr_t&) const
 {
 return true;
 }
 bool operator!=(const nullptr_t&) const
 {
 return false;
 }
 private:
 // Not allowed to get the address
 void operator&() const;
} nullptr = {};

I would like to know if there is any actual flaw in this completed implementation or if there is a difference in the behaviour compared to the C++11 type std::nullptr_t besides the namespace that I can't see.

asked Dec 4, 2012 at 23:18
\$\endgroup\$

2 Answers 2

13
\$\begingroup\$

At the moment, your implementation allows

auto& p = nullptr;

This is forbidden in C++11 as nullptr is an rvalue. You also do not allow the following:

auto p = nullptr;
auto pp = &p;

While C++11 does allow it. You are also missing overloads for comparison operators.

A simple workaround would be to remove the operator& overload and add a macro:

#define nullptr (nullptr_t())

Also, I'd generally use struct X { ... } const x; instead of const struct X { ... } x;.

answered Dec 5, 2012 at 15:28
\$\endgroup\$
7
\$\begingroup\$

Another thing I forgot at the time is that the standard specifies that sizeof(nullptr) shall be equal to sizeof(void*).

3.9.1 - Fundamental types

3.9.1.10 A value of type std::nullptr_t is a null pointer constant (4.10). Such values participate in the pointer and the pointer to member conversions (4.10, 4.11). sizeof(std::nullptr_t) shall be equal to sizeof(void*).

So technically speaking, I should have added padding to my class:

class nullptr_t
{
 // To ensure the size
 // Should be correctly aligned
 void* padding;
 // ...
} const nullptr;
answered May 22, 2013 at 11:06
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Could you provide full implementation including C++11 improvements to nullptr ... I would be grateful. \$\endgroup\$ Commented Jul 10, 2016 at 21:44
  • \$\begingroup\$ That sizeof requirement is a nuisance. I see two issues with adding that padding: 1) I'm not sure that copying around an uninitialized void * is well-defined. I considered replacing it with unsigned char padding[sizeof(void *)], but that didn't solve the next issue, nor would adding empty copy operators. 2) Including a private non-static member variable breaks POD-ness, at least before C++11. I don't see a good way around this. \$\endgroup\$ Commented Jun 19, 2018 at 11:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.