7

I'm trying to replace heavy QString class with the lighter alternatives (QStringRef/QStringView). The problem is that Qt widgets don't consume these classes by any mean. For example, the QLabel::setText method requires const QString& as an input parameter, making my improvement useless.

I'm confused with this discrepancy. Is that on purpose? Is there any reason for that? What should be the use case for QStringView if at the end of the day no one consumes them?

Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40

2 Answers2

4

QString, QStringRef and QStringView have different use cases:

  • QString: the default class to store a string in Qt. It uses implicit sharing to avoid unneeded (read only) copies. Note that you may construct it efficiently by using f.ex. QStringLiteral for static strings:

    [...] For most purposes, QString is the class you want to use. It is used throughout the Qt API [...]

  • QStringView: is useful as a function parameter when you do not want to store the string (and care about the overhead of constructing a QString):

    QStringView is designed as an interface type; its main use-case is as a function parameter type. When QStringViews are used as automatic variables or data members, care must be taken to ensure that the referenced string data (for example, owned by a QString) outlives the QStringView on all code paths, lest the string view ends up referencing deleted data.

    If you want to give your users maximum freedom in what strings they can pass to your function, accompany the QStringView overload with overloads for [...] QString if you store an unmodified copy of the string and thus would like to take advantage of QString's implicit sharing.

    QLabel should definitely store the text string (to paint it during the paint event or to implement the getter function). So, providing a QStringView overload wouldn't be an improvement.

  • QStringRef: is useful for low-level string parsing:

    This class is designed to improve the performance of substring handling when manipulating substrings obtained from existing QString instances. QStringRef avoids the memory allocation and reference counting overhead of a standard QString by simply referencing a part of the original string. This can prove to be advantageous in low level code, such as that used in a parser, at the expense of potentially more complex code.

Note that only QString takes ownership of the string, for the other two, it is the programmer who should ensure the referenced string still exists.

Conclusion: QString is the right class to use in the interface of QLabel::setText.

Further reading

m7913d
  • 10,244
  • 7
  • 28
  • 56
  • I have forgotten of the obvious fact that `QLabel` stores this value. Considering that I would agree that `QLabel::setText` shall not have overloads for `QStringView`. – Dmitry Kuzminov Jul 15 '20 at 21:06
  • After returning back to my code I've discovered that `QLabel::setText` accepts the `const QString&` as an input parameter. That is neither `QString` (passed by value) nor a string view. So I agree that `QString` is the right class to use, but that actually this right approach is not currently used. – Dmitry Kuzminov Jul 20 '20 at 04:55
  • I do not understand the issue about `QLabel::setText` accepting a const reference. `QLabel` will construct an implicitly shared copy of the string (which is very fast). Note that Qt uses const references by default instead of passing by values as it avoids the small overhead related to copying implicitly shared classes. – m7913d Jul 20 '20 at 09:34
2

Qt uses CoW (Copy-on-Write) principle for its own containers. It is a bit outdated technique, but works ok for a mostly single thread UI framework like Qt.

The official documentation eleborates more on that here: https://doc.qt.io/qt-5/implicit-sharing.html

As @m7913d noted in the comments and in his answer, most widgets do create a local copy inside and that is when the CoW principle makes things fast.

Anyway, we are dealing with UI here, lots of drawing, OS API, abstraction layers, giant (compared to string sizes) framebuffers and what not. May be they will add StringViews to their API later and change their architecture, add SSO for QStrings, but apperently this is not an emergency now.

Qt used to be progressive like 10-15 years ago. CoW, Qt containers, lots of libs for everyday things, usability. But now all this stuff is lagging behind modern C++ and STL and Qt encourages their users to rely on STL containers and use Qt analogs only for operations with API.

No one wants a parallel STL and a Qt version of every lib ever.

As for QStringView I think its purpose is to provide a modern view mechanism for user classes which interact with QStrings. For example, you use QXML to extract lots of data from xml files. And then you have to analyze this data somehow - you do not need to interact with API, but you already have QStrings. To make things up to date and a bit faster - here you are - QStringView.

Vasilij
  • 1,861
  • 1
  • 5
  • 9
  • 1
    As long as there exist classes like `QStringRef`/`QStringView`, the user like me may try to use them (and that is reasoneable for improving the efficiency of the client's code). The widgets are the "appliances" for the client, and should accept any native string representation if it is possible to avoid additional copying. Are there obvious technical reasons why that can't be done? – Dmitry Kuzminov Jul 15 '20 at 09:25
  • 2
    If `QString`s are copy-on-write, then there's no reason **to** use views instead... is there? Not without tests/benchmarks proving they're worth the hassle at all. And indeed, if (I don't know) the views expect to refer to some longer-lived underlying string object, then one could not safely do so. – underscore_d Jul 15 '20 at 09:37
  • 1
    @underscore_d if I have a string literal, c-string or std::string, does QString copy the memory upon the first QString instance creation? I guess it does, otherwise it could get into a trouble if I destroy the std::string or pure `char[]` that Qt doesn't control. But with the QStringView I can avoid this copying. – Dmitry Kuzminov Jul 15 '20 at 09:42
  • I edited my answer (sorry for that), so it answers a part of your comment. I beleive copying a QStringView is faster than copying a QString, but without tests this is just an opinion. But anyways passing const QString & or QStringView doesn't involve memory allocations - that is probably fast enough for a GUI. – Vasilij Jul 15 '20 at 09:45
  • 1
    My saying "one could not safely do so" was probably too paranoid; so long as the function receiving a view makes sure it copies it to a new string wherever required, instead of storing just another view to the original, expiring string... then that would be fine. Fwiw, I don't disagree with you at all that this is a desirable feature; I have asked the same question about other libraries. However, it usually seems that the task of using views is not trivial to implement, and no one has thought it worth doing yet. Maybe other GUI processes eg layout/rendering are presumed to dwarf string copies? – underscore_d Jul 15 '20 at 09:47
  • 1
    @Vasilij Passing `QString const&` can involve memory allocations, if that invokes construction of a temporay `QString` from a string literal or other convertible type. However, I think your other point, that this isn't necessarily the worst bottleneck in the GUI, is a good one. – underscore_d Jul 15 '20 at 09:49
  • Dmitry, thats a good point. QString constructor is not constexpr. But translation mechanism implies dynamic string allocations for all user-visible strings. – Vasilij Jul 15 '20 at 09:55
  • Ok, the reasoning about QXml is valid. Taking that into consideration I can agree with Marco that the rest is a reasonable feature request. – Dmitry Kuzminov Jul 15 '20 at 09:57
  • @underscore_d, sure, thanks. I meant lvalue const ref and forgot about rvalues. – Vasilij Jul 15 '20 at 10:00