[Development] Question about QCoreApplicationData::*_libpaths

Thiago Macieira thiago.macieira at intel.com
Wed Jan 20 22:17:35 CET 2016


On Wednesday 20 January 2016 20:05:08 Kevin Kofler wrote:
> Thiago Macieira wrote:
> > We can only do that efficiently if we drop CoW. Creating an adapting API
> > is easy; making sure we don't do unnecessary copies because we've lost CoW
> > is the hard part.
> 
> Would it be possible to wrap a QSharedDataPointer<VectorData<T> >, where
> class VectorData<T> : public QSharedData, public std::vector<T>? That would
> still be layered above std::vector (and d.data() would give you something
> that is-a std::vector) yet CoW. Or are there reasons why such an approach
> would not be workable for std::vector?

This causes double indirection to the data, something we've worked hard to 
avoid. The most common operation you do on a vector is access an element, so 
that should be fast.

Here's what the begin() const functions look like:

libc++:	    		return __make_iter(this->__begin_);
libstdc++:	      return const_iterator(this->_M_impl._M_start);
QVector:		return d->constBegin();
	->		return data();
	->		return static_cast<const T *>(QArrayData::data());
	->		return reinterpret_cast<char *>(this) + offset;
(all inline)

or in my implementation, QArrayDataPointer::data() does:
		return ptr;

The important thing to note is that there's exactly one pointer dereferenced 
at all: this. Current QVector already loses a little by having 
QArrayData::offset added.

But if we did what you suggest, then here's what QVector::begin() const would 
look like:

	typename std::vector<T>::const_iterator begin() const
	{ return this->d->begin(); }

Now we needed to dereference this *and* the d pointer. This means potentially 
two cachelines being read from and there's a data dependency, which in turn 
means potential pipeline stall.

> Now I think the current QVector implementation is fine, but I'm also not
> convinced wrapping std::vector requires dropping CoW. The problems would
> probably show up somewhere else.

The options are:
 a) accept the extra dereferencing
 b) not wrap std::vector, but continue with our own array management
 c) drop CoW

As I told Lars last night / this morning over IRC, what I would love to have 
is an improved version of Qt 5's unsharable containers mode:

	template<typename T>	using QVector<T> = QtTools::Vector<T, CopyOnWrite>;
	using QString = QtTools::String<CopyOnWrite>;

where QtTools::Vector<T, Trait> can do both CoW and non-CoW modes. You'd be 
able to write code like:

QString foo()
{
	QtTools::String<Unsharable> s(size, Qt::Uninitialized);
	fill(s.data(), size);		// no useless detach() emitted!
	foreach (auto ch : s)		// ditto
		process(ch);
	return s;				// move-construction "steals" buffer
}

QtTools::String<Unsharable> s = foo();	// move-construction attempts to steal

The Unsharable modes for the containers would have the same complexity and 
behaviour as the Standard Library counterparts. But they'd do more, since 
they'd interoperate with the CoW containers too.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center




More information about the Development mailing list