|
||||
Section 18:
|
[18.17] Why am I getting an error converting a Foo** → Foo const**?
Because converting Foo** → Foo const** would be invalid and dangerous. C++ allows the (safe) conversion Foo* → Foo const*, but gives an error if you try to implicitly convert Foo** → Foo const**. The rationale for why that error is a good thing is given below. But first, here is the most common solution: simply change Foo const** to Foo const* const*: class Foo { /* ... */ }; void f(Foo const** p); void g(Foo const* const* p); int main() { Foo** p = /*...*/; ... f(p); // ERROR: it's illegal and immoral to convert Foo** to Foo const** g(p); // OK: it's legal and moral to convert Foo** to Foo const* const* ... }The reason the conversion from Foo** → Foo const** is dangerous is that it would let you silently and accidentally modify a const Foo object without a cast: class Foo { public: void modify(); // make some modification to the this object }; int main() { const Foo x; Foo* p; Foo const** q = &p; // q now points to p; this is (fortunately!) an error *q = &x; // p now points to x p->modify(); // Ouch: modifies a const Foo!! ... }If the q = &p line were legal, q would be pointing at p. The next line, *q = &x, changes p itself (since *q is p) to point at x. That would be a bad thing, since we would have lost the const qualifier: p is a Foo* but x is a const Foo. The p->modify() line exploits p's ability to modify its referent, which is the real problem, since we ended up modifying a const Foo. By way of analogy, if you hide a criminal under a lawful disguise, he can then exploit the trust given to that disguise. That's bad. Thankfully C++ prevents you from doing this: the line q = &p is flagged by the C++ compiler as a compile-time error. Reminder: please do not pointer-cast your way around that compile-time error message. Just Say No! (Note: there is a conceptual similarity between this and the prohibition against converting Derived** to Base**.) |