24

Why does it even compile?

struct UE{
    UE(bool a = true) {  };
//  UE(){}; // if UE took no initial args and called below, gcc will complain.
};
class VA {
    protected:
            UE ue;
    public:
            VA();
};
VA::VA()
{
    ue = new UE(true); // ???why???
//  ue = new UE(); // will complain
}

I tried with gcc (GCC) 4.6.2. How can I assign a struct with a pointer?

alk
  • 69,737
  • 10
  • 105
  • 255
BetterWang
  • 243
  • 1
  • 4

4 Answers4

29

You're hitting the fact that you didn't mark your constructor as explicit, and thus it can be used for implicit conversions.

new UE(true) returns a pointer. All pointers can be implicitly converted to bool, resulting in true if they are non-null. UE can be implicitly constructed from a bool. So in effect, the pointer returned by new is converted to bool, which is converted to UE using your constructor, and then the copy assignment operator of UE is called. Of course, the memory allocated by new is leaked.

The take-home message is: always mark your single-argument constructors as explicit unless you actually want them to be usable for implicit conversions. By "single-argument constructor," I mean one which can be called with a single argument. Either because it has one parameter, or it has more and all parameters after the first have default arguments.

Destructor
  • 14,123
  • 11
  • 61
  • 126
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 2
    Thanks, that explains everything. – BetterWang Feb 11 '14 at 20:36
  • I really wish gcc would generate a warning for this. It seems like it ought to be distinguishable from "things you might want to do". Cppcheck (1.63.1) did not catch it. g++ 4.7.2 did not catch it. – Colin D Bennett Feb 11 '14 at 23:12
  • @ColinDBennett You mean because of the `new`? Modern C++ code shoudln't contain many `new` calls anyway, so it would apply quite seldom. And with any other way to obtain a pointer, such conversion is fair game and I would be quite annoyed if I intended it and got a warning. – Angew is no longer proud of SO Feb 12 '14 at 08:02
  • @Angew possibly the warning could be predicated on the implicit conversion from a *pointer type* to *bool* being passed as a function or constructor parameter. Typically the pointer to *bool* conversion is most useful an appropriate when used as the condition to flow control statement like `if (my_ifstream) { ... }` or `while (p) { p = p->next; ... }`, but I would personally like a warning if I pass a pointer as a parameter a function argument declared as bool. – Colin D Bennett Feb 12 '14 at 21:00
8

There is an implicit conversion from any pointer to bool. Hence this code is implicitly calling the single argument constructor after converting the pointer to a bool value

One way to fix this is to make the single parameter constructor explicit.

struct UE{
    explicit UE(bool a = true) {  };
};

This will prevent the code from compiling unless the constructor is explicitly invoked

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

Any scalar type can be converted to boolean value true or false depending on whether its value is equal to zero or not..

In this statement

ue = new UE(true); 

the implicitly defined by the compiler copy assignment operator is called. As expression new UE( true ) is not equal to zero then it can be converted implicitly to boolean value true. Class UE has conversion constructor

UE(bool a = true);

that converts an object of type bool to an object of type UE.

To prevent such usage you should define the constructor as explicit

explicit UE(bool a = true);
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

If you mark you constructor explicit this won't work:

explicit UE( bool a = true) {  };

this is because there is an implicit conversion from the pointer to a bool, we can see this is allowed from draft C++ standard section 4.12 Boolean conversions says (emphasis mine):

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740