On January 16, 2016 00:44:57 Kevin Kofler <kevin.kof...@chello.at> wrote:
> Marc Mutz wrote: > >> On Friday 15 January 2016 03:58:12 Kevin Kofler wrote: >>> So why not just add a QOptional that works the same as std::optional? >> >> a) because we can't (we don't yet require the necessary language features) > > A QOptional<T> that works with Qt's implicitly-shared data objects (such as > QStringList, which is what it is wanted for here) only really needs this: > T data; > bool present; > (I guess that order will give the better memory layout than the opposite > order.) If present is false, you just put a default-constructed T into the > (ignored) data field, which will simply have a null d-pointer and thus cost > you almost no time to construct. I don't see what further language features > are needed for us. > >> b) because once introduced, people will add all kinds of Qt-specific stuff >> to it, making it impossible to replace it with std::optional down the >> road. And since it will be good enough for the low demands of Qt >> development, it will no longer see development and fall behind the state >> of the art. > > So what? Qt users are not forced to use it, and I'm sure several will, maybe > BECAUSE of the "all kinds of Qt-specific stuff" that people actually find > convenient. Actually this convince is hurting you if you need performance. I would prefer the convenience on top of lower level api. >> <rant> >> Consider QVector: it has been Qt-ifed by both adding (technically) useless >> duplicate Qt-ish API, CoW, and a Qt-specific type classification scheme >> plus corresponding optimisations that make it very hard to argue for >> std::vector use instead. The Qt community had two decades where they could >> have influenced the direction std::vector would take so it could allow the >> same optimisations that QVector has, but the time and energy was instead >> put into re-writing the containers for every major release (yes, for Qt 5, >> too, and Thiago's Qt 6 QVector again looks much different from the Qt 5 >> one). > > But the Qt-ish API and the CoW are exactly what makes the Qt containers NICE > to use, unlike the STL. I have found myself more than once using QtCore in a > project solely and explicitly for the container classes! They are what makes > C++ a nice-to-use language. It makes also easy to shoot yourself in the foot. The Qt containers love to malloc. ;-) I really prefer the the proposed ranges API. >> The CoW makes QVector slow and increase code size, leads to hidden >> detaches that not even Qt experts regularly avoid in their daily work, and > > Well, I am well aware of the issue, and know to use e.g.: > static_cast<const QVector &>(vec).first() > when needed. (I guess this is actually more efficient than the popular > .at(0) workaround. It is definitely not less efficient.) But normally I will > just always operate on const data structures (usually const references) when > I'm not writing to them, so I don't have to cast anything. (And of course, > when I'm writing to them, chances are the detach is exactly what I want or > need.) > >> doesn't even work properly because you can take iterators into a QVector >> and, after copying the vector, change both copies through the iterator >> into the first. That is a conscious trade-off because making the container >> unsharable, as it must become once it hands out iterators, would make CoW >> fail to take effect _all the time_. But it leads to careless copying of >> QVectors that also doesn't really help with porting to std::vector. > > So don't use iterators into QVector, use indexes, it's a random-access > container. The non-const operator[] that you use then DOES detach when > needed. (And of course, for read-only iteration, foreach works great.) > The only container type where I found iterators to be truly useful is maps > (QMap, QHash, etc.), where the iterator can give me both key and value at > once and saves me the key lookup. I prefer algorithms which are based on iterators to handwritten loops. They are easier to parallise in the future too. >> All the while - and I don't believe I'm saying this - std::vector *blazes >> the trail* with move semantics, emplace_back and stateful allocators >> (making QVarLengthArray all but useless). Does QVector use move semantics? >> No. > > Move semantics are mainly an ugly way to avoid copies if you don't have CoW. > With CoW data structures, all you save through move semantics is the > reference counting. And move semantics make it easy to shoot yourself in the > foot. (Either you leave behind an invitation for a use-after-free bug, or > you end up swapping instead of assigning, which is also a pessimization.) In my opinion move semantics are about ownership. After using them for some time I really like them to manage resources. Atomics on the other side can produce strange performance bugs with false sharing. I don't believe they are the future in a many core environment where you share cache lines very often. >> Does QVector have emplace_back? No. > > Just like the move semantics, this is also an ugly and complicated way to > avoid a copy if you don't have CoW or merely save the reference counting if > you do. But how is cow working together with the prefetcher. If I have my data outlined in a continuous way like a struct in vector it will be much faster than a pointed array. I really like emplace. I construct objects in a vector which cannot be copied. So the vector is owning all the resources. >> Does QVector have an allocator, even one that, citing Alexandrescu, >> actually deals with allocation? No. > > For the average programmer, an allocator is just an obscure thing that shows > up as a template parameter in all the error messages making them ugly and > unreadable. > > The fact that Qt containers only have the template arguments that are > intuitively templated on (e.g., QVector has only the contained type as a > template parameter) is really a feature, not a bug. > >> Does QVector, even with Q_PRIMITIVE_TYPE payloads, expand to less code as >> std::vector? No: https://codereview.qt-project.org/145587 (comment from >> 01-14 11:21). > > So there is room for improvement there. But in the end, this is not going to > be the deciding factor for which implementation to pick for most > programmers. And in the end, you need to compare QVector with class > libraries in programming languages that offer comparable convenience, not > with the C++ STL. Hmm most other languages I know provide more convenience than Qt but are slower. I think you pick C++ in the context of speed. So we should provide a wrapper around std vector with cow. > If you try to force programmers to use the STL, chances are they will rather > just switch to some other programming language that offers the semantics > they expect. I know many C++ who avoid Qt because we user or own containers. It really depends not everybody has the same taste or needs. I think we should provide both levels. >> Does QVector have a debug mode comparable to that of std::vector >> implementations? Nope. > > I never had any need for that. > >> Or: The only reason I ever used std::list was to use its splice() feature. >> Does QLinkedList have splice()? No, of course not. Because it _cannot_ >> (it's CoWed: how do you take ownership of nodes if the they are shared? By >> copying all other nodes in a detach()?). > > Then use std::list if it suits your use case better. Just don't force > everyone else to use it. > > Personally, I also don't normally have a use for QLinkedList, QList suits my > needs just fine. :-p (In fact, QList was changed from the linked list it was > in Qt 3 to an array of pointers in Qt 4 exactly BECAUSE that's the more > efficient data structure in most practical applications.) QList is really a trap. struct Entry { QString text; bool isHtml; } ; QList<Entry> list; Do you see the problem? > And I simply find the Qt containers to be much nicer to work with as a > whole. In fact, I recently had to use std::priority_queue for a (QtCore- > based) project of mine, a container class that sadly is not implemented in > Qt (*). After attempting to use it directly and cursing about it, I ended up > implementing a Qt-style wrapper around it: > * My data class simply multiple-inherits from public QSharedData, > public std::priority_queue<T>. > * My public class contains a QSharedDataPointer of the above, renames the > methods to names matching QQueue, and in particular adds a dequeue() > method that does both top() and pop(). Null objects (null d-pointer) are > also handled gracefully (the const methods fake an empty queue, the > enqueue (= STL push) method allocates the d-pointer). > So, a few lines of boilerplate, and suddenly the API becomes usable, and CoW > just works. Incidentally, the CoW was also the only way I found to avoid a > copy of the whole queue while initializing while keeping C++98 compatibility > (so no move or swap): > * I need to initialize my priority_queue from a list (actually a QList :-) > but I would have the same issue with QVector or even std::vector). > * There is no push method that takes a whole list of items. > * So I can only: > - either push every item one at a time, which sorts them less efficiently > than a bulk insert, > - or use the constructor that takes iterators, which then leaves me with a > whole std::priority_queue to copy. My CoW wrapper avoids that copy. > * And my API wrapper actually accepts the QList (or actually any list type > with constBegin() and constEnd() methods) directly instead of requiring > iterators. > > (*) I did find one third-party QPriorityQueue class, but it was just a > wrapper around std::priority_queue that was neither CoW nor had API > consistency with QQueue, so it was better to implement my own. So why we force CoW on people. Most of the time I don't need it. And I don't need atomics if CoW is handy. We should provide a low level version too. >> This is why we need to stop duplicating std API. It's not Qt's core >> competency to meddle with things we only have a half-interest in. It's fun >> to write QOptional. Until it isn't anymore. And then the (Qt) world needs >> to live with the poor-man's std::optional for the next few decades. > > I think having more Qt containers would actually be a good thing, not > something to be scared of. It really depends what you want to do. I would prefer it we had a CoW wrapper around std vector. Best of both worlds. > Kevin Kofler > > _______________________________________________ > Development mailing list > Development@qt-project.org > http://lists.qt-project.org/mailman/listinfo/development -- Sent from cellphone, sorry for the typos _______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development