[Development] QString and related changes for Qt 6
Matthew Woehlke
mwoehlke.floss at gmail.com
Wed May 13 17:17:03 CEST 2020
On 12/05/2020 17.21, Thiago Macieira wrote:
> On Tuesday, 12 May 2020 08:42:28 PDT Matthew Woehlke wrote:
>> How will this work? As I understand, the main advantage to
>> QStringLiteral is that it statically encodes the *length* as well as the
>> data. This isn't possible with raw literals, which are merely
>> NUL-terminated.
>
> Black magic!
>
> I mean, templates and constexpr.
Yeah... I'm not sure what I was thinking when I wrote that...
Oh, wait...
>> I don't see us ever getting rid of some form of QString
>> literal short of templatizing *everything* that takes a T* (for T in
>> char, char16_t, etc.) to take a T(&)[N] instead.
...I was thinking this. You might be able to escape this for methods
that don't take both QString *and* QStringView. Otherwise, well, see my
later message on that point.
And on that note...
> But QStringView(u"foo") should call that first constructor. Doesn't it? I
> never remember if the literal decays to pointer before the overload
> resolution.
Uh... no, actually it doesn't. (Which TBH smells a bit like a defect to
me, but we're stuck with it for now.)
Note: https://godbolt.org/z/FbjQkM
(That was experimenting with QString/QStringView overload
disambiguation, but also includes the relevant ctors. Comment out the
templated overload of `foo` and one of the others, and you'll see that
the invocation with a literal calls the "wrong" ctor.)
So, we either need to retain literals in some form, or, as I was saying,
every method needs to have a templated flavor for string literals.
>> The "nice" thing about QStringView is that it does not have ownership;
>> you have to be careful about how long you hold onto it lest it turn into
>> a dangling pointer. You can't construct a QString from any old bag of
>> byt^Wcharacters because a QString is implicitly valid until it is destroyed.
>
> That's the problem we've had with QStringLiteral and QString::fromRawData().
>
> You *can* create it from read-only data and tell it never to try to modify.
> The trick is guaranteeing that it remains valid until the last user finished
> using it. Because of copy-on-write, that last user can be much later than the
> statement that created the QString in the first place.
Right, but if you're using QStringLiteral / QString::fromRawData, you
"know" you're taking on that responsibility. (And for QStringLiteral,
you only run into problems in some instances with library unloading,
which is a non-issue for many applications.)
What I worry about with trying to avoid QStringView is that we either
lose the ability to avoid copies when the input is a *temporary* (e.g.
stack-allocated) buffer, or else we silently accept such uses and
produce broken programs.
Note that you can't rely on adding non-const overloads as a work-around;
the string might be coming from an intermediate function that doesn't
have a non-const overload, but was called with a (non-const) temporary
buffer.
Example:
void foo(char const* s)
{
...
method_taking_qt_string(s);
...
}
void bar()
{
char buffer[MAX_SIZE];
...do stuff to put data in buffer...
foo(buffer);
}
Non-owning QString is dangerous. QStringLiteral is less dangerous
because it is almost never used with non-rodata storage (and indeed, I
would consider any such usage highly suspect, if not outright broken).
QString::fromRawData is dangerous, but "obviously" so.
We should not implement any way of creating a non-owning QString that is
not explicit, and if we adhere to that, I don't see us *not* wanting
QStringView in many instances.
--
Matthew
More information about the Development
mailing list