简体   繁体   中英

Why I don't get compiling error when assigning const ptr to const reference?

I was working on a project and got a 'strange behavior' that I don't understand, it's about passing const ptr to assign const ref (or const ptr as const ref parameter) does compile but why / how ? (I just want to understand) I did a smaller example code just for the test. PS: Sorry if there's mistake/misunderstanding, I'm not an English native speaker

I compiled with -Wextra -Wall

class dummy
{
public:
  dummy(const bool &run): _dummy_run(run){}
  void printRun()
  { std::cout << "RUN: " << _dummy_run << std::endl; }
private:
  const bool &_dummy_run;
};

int main(int ac, char **av)
{
  const bool *nullboolean = nullptr;
  const bool *booleanptr = new bool(true);

  /// Question 1
  /// How / why passing a const ptr to a const reference is valid ?
  dummy dummy_null(nullboolean);
  dummy dummy_new(booleanptr);

  /// Question 2
  /// Why passing const ptr to const ref is allowed but not ptr to ref ?
  const bool &cboolean = booleanptr;

  // bool &boolean = booleanptr;
  // => error: cannot bind non-const lvalue reference of type ‘bool&’ to an rvalue of type ‘bool’                                                                                   

  /// Question 3
  /// What happened here (print 191) ? There isn't any error on valgrind
  dummy_null.printRun(); // Print 191                                                       
  dummy_new.printRun(); // Print 1                                                                                 

  return 0;
}

My questions are why it compile successfully when passing a const ptr to a const reference ? Why it compile with const reference but not for normal reference ? Why I have a printed value like "191" (see code) when printing the bool value ? (would expect 0, 1, or an error on valgrind) I would be glad if somebody can explain to me or have a link to understand what happened here ? Thanks !

There are two things happening here. Both are kinda crap, and neither are really your fault.

First, when you take a const bool* and pass it into a constructor taking const bool& , the compiler knows you didn't dereference it so it looks for a way to still do what you asked.

It can get a bool , implicitly (ie without a cast), by checking whether the pointer is nullptr (just like it does with if (booleanptr) ). Then, that temporary bool is used to initialise the reference in the constructor/function argument, which it can do because it's a const reference.

So that's bad enough.

Second, though, is that you initialised a member from that reference, but it's immediately dangling because a temporary's lifetime isn't extended that far. It dies when the constructor call ends. That's why the printed output is strange: you're doing undefined things by trying to use a dangling reference.

(In practice, the bit pattern now in memory is likely not the bit pattern that the implementation recognises as "true" or "false"; in fact I would bet it uses '0' and '1' internally and just outputs the int version of the bool. But that's the implementation's choice and anything else could have happened instead.)

All this confusion comes from two things:

  • Your pointee type and referent type ( bool ) happened to be the same;
  • C++ has silly transparent conversions that you can't see!

why it compile successfully when passing a const ptr to a const reference ?

EDIT: Because your pointer is being converted to a temporary bool ie your reference is set to a temporary false for nullptr and a temporary true otherwise.

Why I have a printed value like "191"

EDIT: Consequently, by the time you print, this temporary has gone out of scope so your pointer de-refence is Undefined Behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM