[Development] Question about QCoreApplicationData::*_libpaths

Bubke Marco Marco.Bubke at theqtcompany.com
Sat Jan 16 02:40:02 CET 2016


On January 16, 2016 00:44:57 Kevin Kofler <kevin.kofler at 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 at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development

--
Sent from cellphone, sorry for the typos



More information about the Development mailing list