0

When initializing with a pointer a nullptr can be ambiguous if there are multiple constructors accepting a pointer argument.
You can solve this by casting C cast or static_cast, example:

#include <iostream>
#include <cstddef>

using namespace std;

struct A{
    A(int*){ cout << "int constructor" << endl;}
    A(double*) { cout << "double constructor" << endl;}
};

struct B{
    B(std::nullptr_t) { cout << "nullptr constructor" << endl;}
    B(int*){ cout << "int constructor" << endl;}
    B(double*) { cout << "double constructor" << endl;}
};

int main(){
    //A a(nullptr); constructor is ambiguous 
    A a1((int*)nullptr);// int constructor
    A a2(static_cast<double*>(nullptr));// double constructor

    B b(nullptr);// nullptr constructor
    return 0;
}

I included B to illustrate that a constructor with std::nullptr_t exist and is possible but for this question let's focus on A.

From "Why use static_cast(x) instead of (int)x?" I understand the most dangerous thing about C cast being you don't know which will be used:

The main reason is that classic C casts make no distinction between what we call static_cast<>(), reinterpret_cast<>(), const_cast<>(), and dynamic_cast<>(). These four things are completely different.

Are any of these casts unsafe for a nullptr or can you safely use the C-style cast?

turoni
  • 1,345
  • 1
  • 18
  • 37
  • 1
    Don't use the C-style cast. As explained in the question that you linked, you should always prefer the c++ cast versions over the C-style version. It also makes your code clearer, you are clearly stating what you are doing. – Blasco Nov 30 '17 at 11:11
  • If you sometimes want to construct without a parameter, you could of course also have a default constructor `A()` and skip the `nullptr`. – Bo Persson Nov 30 '17 at 13:46

2 Answers2

2

A reinterpret cast is unsafe irrespective of what you're casting - the point is you're forcing the compiler to ignore it's own set of (very good) rules and trust your (usually wrong) intuition.

I consider dynamic_casting also somewhat hazardous since it allows you to compile down-casting and side-casting. Sometimes when just starting to work with this this can cause confusing NULL pointers appearing or run-time errors.

In your example it doesn't matter since the conversion is trivial, so you "can" use anything, but you probably shouldn't. The C-style case will probably be static since it's hard-coded in compilation time, so in your case it won't matter (but you can't be sure! it's not guaranteed!). This is more of a be safe convention - use static_cast since that's what you want to do, and that's the way to guarantee it. If your code becomes more advance/complex/difficult the "be safe" rule can really save you from nasty bugs.

In general, C++ should contain no native C, at least as a beginner, probably most of the time.

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • Can but shouldn't is what I was looking for. I don't see how any of the casts can go wrong starting from a nullptr but I'll stay with safe casts. – turoni Nov 30 '17 at 11:19
  • 2
    The opinion on dynamic_cast is nonsense. The compiler ignores no rules, in fact it checks the validity and can throw or return null. – MSalters Nov 30 '17 at 13:45
  • @MSalters While I realize down(side)-casting may be necessary at times, it's still not "safe" in the sense that can cause run-time errors/unexpected null values (think beginner perspective). I didn't think I should elaborate on my opinions, but if you feel it's nonsense what do you suggest? A lesser warning? – kabanus Nov 30 '17 at 14:37
  • @MSalters Tried to do better by you, feel free to edit in. – kabanus Nov 30 '17 at 14:40
  • @kabanus: FYI: `reinterpret_cast`s are not a priori unsafe. – Nicol Bolas Nov 30 '17 at 16:19
  • @NicolBolas it's the same kind of safety issue as the one Msalters disregarded. I realize you two know what you're doing, but it seems you are missing the point of the word "safe". Everything is safe if you're perfect at what you're doing. The question is where is it easiest to make mistakes. – kabanus Nov 30 '17 at 16:54
  • @kabanus: The sentence, "A reinterpret cast is unsafe irrespective of what you're casting" is a statement with no equivocation, conditions, or anything else. As such, it gives an impression that `reinterpret_cast` cannot be used safely. That impression is incorrect. It doesn't matter who you're talking to; you should not put incorrect information in an answer. – Nicol Bolas Nov 30 '17 at 17:00
  • @NicolBolas I stand by that sentence. It's easy to create difficult bugs with reinterpret compared to most other stuff you can do with C++. Only when you understand the dangers, so to speak, you should decide if and how to. I don't know if you get what I mean by safe as a coding practice, but if you do and have better (correct-er) phrasing I'd be happy to use it. – kabanus Nov 30 '17 at 17:22
0

I feel that if the class allow multiple pointer types to construct then the class author should take design responsibility for explicit null pointers.

The default position is that null pointers are not handled, which is perfectly valid. The author can add a nullptr_t or no-args constructor if they want to handle explicit null pointers, but if not, the user should take it as a firm design warning.

Gem Taylor
  • 5,381
  • 1
  • 9
  • 27