diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index da890e9..a24dc5c 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -7790,7 +7790,7 @@ Overload rule summary: * [C.161: Use nonmember functions for symmetric operators](#Ro-symmetric) * [C.162: Overload operations that are roughly equivalent](#Ro-equivalent) * [C.163: Overload only for operations that are roughly equivalent](#Ro-equivalent-2) -* [C.164: Avoid conversion operators](#Ro-conversion) +* [C.164: Avoid implicit conversion operators](#Ro-conversion) * [C.165: Use `using` for customization points](#Ro-custom) * [C.166: Overload unary `&` only as part of a system of smart pointers and references](#Ro-address-of) * [C.167: Use an operator for an operation with its conventional meaning](#Ro-overload) @@ -7899,7 +7899,7 @@ Be particularly careful about common and popular names, such as `open`, `move`, ??? -### C.164: Avoid conversion operators +### C.164: Avoid implicit conversion operators ##### Reason @@ -7912,27 +7912,37 @@ By "serious need" we mean a reason that is fundamental in the application domain and frequently needed. Do not introduce implicit conversions (through conversion operators or non-`explicit` constructors) just to gain a minor convenience. -##### Example, bad +##### Example - class String { // handle ownership and access to a sequence of characters - // ... - String(czstring p); // copy from *p to *(this->elem) - // ... - operator zstring() { return elem; } + struct S1 { + string s; // ... + operator char*() { return s.data(); } // BAD, likely to cause surprises }; - void user(zstring p) + struct S2 { + string s; + // ... + explicit operator char*() { return s.data(); } + }; + + void f(S1 s1, S2 s2) { - if (*p == "") { - String s {"Trouble ahead!"}; - // ... - p = s; - } - // use p + char* x1 = s1; // OK, but can cause surprises in many contexts + char* x2 = s2; // error (and that's usually a good thing) + char* x3 = static_cats(s2); // we can be explicit (on your head be it) } -The string allocated for `s` and assigned to `p` is destroyed before it can be used. +The surprising and potentially damaging implicit conversion can occur is arbitrarily hard-to spot contexts, e.g., + + S1 ff(); + + char* g() + { + return ff(); + } + +The string returned by `ff()` is destroyed before the returned pointer into it can be used. ##### Enforcement