Reputation: 41
Let's take the following source code:
const ushort *QString::utf16() const
{
if (IS_RAW_DATA(d)) {
// ensure '\0'-termination for ::fromRawData strings
const_cast<QString*>(this)->reallocData(uint(d->size) + 1u);
}
return d->data();
}
reallocData() modifies the d-pointer class member d, see https://code.woboq.org/qt5/qtbase/src/corelib/tools/qstring.cpp.html#_ZN7QString11reallocDataEjb . What if the QString object is const? According to https://en.cppreference.com/w/cpp/language/const_cast modifying const objects with casting away constness is UB:
struct type {
int i;
type(): i(3) {}
void f(int v) const {
const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
}
};
type t; // if this was const type t, then t.f(4) would be undefined behavior
t.f(4);
Do we have UB in this particular piece of code (QString::utf16())?
Upvotes: 1
Views: 230
Reputation: 25526
This is undefined behaviour if (and only if) the object in question was originally created const
:
QString const sc("whatever");
sc.utf16(); // undefined behaviour!
QString s("whatever");
QString const& scr = s;
scr.utf16(); // NOT undefined behaviour!
Still, casting away constness is a very bad idea, as, within the function, you never know if the object in question is a true const object or is only a pointer/reference to a object originally created non-const, so there is always immanent danger of UB!
Best is just not having the function const:
const ushort* QString::utf16()
{
//...
}
As the case might be, users then are forced to create a non-const copy, even if the original object actually was non-const, but this is always better than risking UB!
Upvotes: 1
Reputation: 37520
This would indeed be an UB if QString
object on which this method in invoked is const-qualified:
QString const str{"whatever"};
str.utf16();
Note that important part here is that object is const-qualified, not that the method is const-qualified.
Upvotes: 6