Hi Matthew, 

Your whole point was relocation but my point was traversing. Relocation can be 
easily fixed by reserve but if traversing is slow it is much harder to remove 
the convenience structures. I don't say we should not provide them, I only say 
they should be on top. 

On January 18, 2016 18:48:07 Matthew Woehlke <mwoehlke.fl...@gmail.com> wrote:

> On 2016-01-16 07:06, Bubke Marco wrote:
>> On January 16, 2016 06:08:14 Kevin Kofler wrote:
>>> I suspect we would lose at least some optimizations from 
>>> Q_DECLARE_TYPEINFO.
>> 
>> std::is_trivially_copyable and other type traits are your friends.
>
> Not really. There is a huge difference between a relocatable type (many,
> if not most), and a trivially copyable type (a lot fewer). Operations
> such as growing the buffer can be vastly more expensive if the item type
> is not relocatable vs. if it is. However, C++ itself currently does not
> provide any support for relocation.

So how many people define there objects as relocatable? Anyway for large 
vectors I use always reserve which is a quite common optimization. For pattern 
were you are holding references in the vector you have to do it anyway. 

> I want to say e.g. std::string is relocatable, but it is certainly not
> trivially copyable. Now, imagine a std::vector<std::string> where both
> the vector and strings are very large. When the vector needs to resize,
> it will have to do a deep copy of ever single item, allocating and
> freeing lots of memory in the process. Compare to QVector<std::string>
> (assume Q_DECLARE_TYPEINFO declares std::string relocatable), which...
> will do a realloc(). Worst case, that's 1 alloc, 1 free, and 1 block
> copy... and 0 ctor/dtor calls.
>
> That's a *significant* difference.
>
> (Even using QString instead of std::string does not help much... the
> QVector still just does a realloc, while std::vector must perform 2*N
> atomic operations.)
>
> ...and then there's QList, which just does a realloc(), *always*.

So you optimized the container for growing with allocations. I don't think it 
is the most common case. Having cache misses in traversing the container can be 
much worse and is much harder to fix than a reserve. 

>
>> There are other pitfalls in the qt containers,  e.g.
>> 
>> if (container.contains(key)) 
>>    auto value = container.value(key);
>> 
>> auto iterator = container.find(key);
>> if (iterator! = container.den()) 
>>   auto value = iterator.value();
>> 
>> The first looks nice but leads to two lookups. And I have seen it very 
>> often. 
>
> Probably because a) it's easier / clearer to read, b) it's MUCH easier
> to write, and c) most of the time the performance doesn't matter enough
> to justify the ugliness of the latter. Specifically, I know I have
> written code like that *in full knowledge* that it's inefficient, simply
> because I don't judge it sufficiently inefficient to justify the ugly
> and obtuse STL syntax.

I don't think it's is so obscure. In Qt we have many obscure patters too but 
you adapt to it. As I was coming from python I found Qt ugly but it changed 
with time. ;-)

> That said, the *correct* fix is:
>
>   auto value = container.maybe_at(key);
>   if (value)
>     do_something(*value);
>
> (...using std::optional or similar)
>
> This is easy to read, easy to write, *and* efficient.

I would prefer ranges. I think the next big step is easy writable parallel 
algorithms and hand written code like that is in my opinion not that 
maintainable. But we will see. 

>> I understand the problem. But my problem is more that I have the
>> atomic pointer which can slow your code done unexpectedly.
>
> Compared to what? The pointer only kicks in during a copy or destroy. At
> the point of the copy, the question is if a deep copy is slower than an
> atomic operation. At the point of destruction, you are probably slow
> anyway, though if it's just a dereference, you have potentially saved a
> heap free.

What about begin? Sorry, why are many other moving away from CoW for small data 
structures? Do we know something what they are not knowing? Atomics with multi 
cores can slow down your code considerable so copying can be smarter in that 
case. 

>> If you provide data structures which are trivially copy able the
>> simply could be moved in memory for a vector which is quite fast.
>
> ...except not nearly so many data structures are trivially copyable as
> you would like to think. Many are *relocatable* (a concept that does not
> yet exist in C++ proper), but *not* trivially copyable.

Actually many of my demanding structures are trivially copyable.  ;-)

> Even move semantics are less efficient than relocation (usually not by
> much, but still by some).
>
>> I don't say that there is no use case for a pointed vector but I can always 
>> do
>> Vector<Entry*>
>
> No, you can't. At best, you'd have to do vector<unique_ptr<Entry>>, and
> you'd still have a leaky abstraction problems. Having the indirection
> built into the container shields you from this.
>
> At best, this seems like an argument that QList should act like QVector
> for relocatable types up to a certain size (said size being greater than
> a single pointer, as is currently the case).

Actually I don't like that magic. You optimising a data structure for one use 
cases which is in many cases easily fixable. I don't think relocation is the 
most common problem. 

> (I'd be inclined to agree with such an argument, incidentally.)
>
> -- 
> Matthew
>
> _______________________________________________
> 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

Reply via email to