Topic: faster version of std::vector


Author: "Hicham BOUHMADI" <hicham@citeweb.net>
Date: 2000/07/19
Raw View
Hi.
By using the STL and especially the STL containers, I found that it is
designed so it only uses by value variables.
This is why when instanciating a vector with a "big" type, it makes thing
very slow...
The solution I found is to use smart pointers.
Depending on what it is intended, you can use auto_ptr, or a custom smart
pointer that can also handle "garbage collection".
The choice of the smart pointer depends on when the contained objects must
be destructed.

You may got some problems with some containers such as the set container:
Your smart pointer should handle correctly the < operator if you use the
default ::std::less predicate. Otherwise, you can instanciate the set
container with your smart pointer and a custom predicate, that knows how to
compare your smart pointers.

I'll be happy if someone can tell me why the STL uses by value variables
instead of references...

Hicham BOUHMADI        hicham@citeweb.net


Stefan Reiss <stefan@reisz.de> a    crit dans le message :
3971ba60@news.ivm.net...
> Hi.
> The vector template might become slow, if its element type has a
non-trivial
> copy semantic.
> such as vector<vector<int> > . On each reallocation the elements must be
> copied, which means allocating memory and copying many elements. (i think
> there is no normal way for a compiler to optimize this away. I heard about
a
> rule that if you call a copy-ctor and then a dtor with the same object,
the
> compiler can optimize, but I think that wont help here.)
>
> But the inner copies could be avoided, if there were a special function ,
a
> "transfer-ctor" , which only redirects the pointers, like in std::swap.
> The transfer-ctor  T(T&t , transfer_t dummy) { ...} assures that
afterwards
> , the new object is like the passed t, and t may be in any valid state (so
> dtor for t might be called later).
>
> I designed a fast_vector with such a transfer-ctor , and modified insert.
>
> The following code took
>   7 seconds with vector
>   1 second  with fast_vector
>
>  vect<int> v(1000);
>  vect<vect<int> >vv;
>  for (int i = 0; i < 10000; ++i)   vv.push_back(v);
>
> it requires only little extension for <vector> and <memory>
> So it might be a good idea for a next standard
>
> Stefan
>
>
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
>


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel M. Pfeffer" <pfefferd@nospam.internet-zahav.net>
Date: 2000/07/20
Raw View
"Hicham BOUHMADI" <hicham@citeweb.net> wrote in message
news:8l1j8r$ihj$1@reader1.imaginet.fr...
> Hi.
> By using the STL and especially the STL containers, I found that it is
> designed so it only uses by value variables.
> This is why when instanciating a vector with a "big" type, it makes thing
> very slow...
> The solution I found is to use smart pointers.
> Depending on what it is intended, you can use auto_ptr, or a custom smart
> pointer that can also handle "garbage collection".
> The choice of the smart pointer depends on when the contained objects must
> be destructed.
>
> You may got some problems with some containers such as the set container:
> Your smart pointer should handle correctly the < operator if you use the
> default ::std::less predicate. Otherwise, you can instanciate the set
> container with your smart pointer and a custom predicate, that knows how
to
> compare your smart pointers.
>
> I'll be happy if someone can tell me why the STL uses by value variables
> instead of references...

Using an auto_ptr in an STL container is forbidden. Many STL algorithms rely
on the fact that an object may be copied without modifying the original (the
object has a copy constructor of form X(const X &)). This is untrue for
auto_ptr, which provides a copy constructor of form X(X &).

Having the container contain objects, rather than pointers (or references)
allows the STL to ignore the problems of ownership and dangling references.
The ownership problem appears when a container that contains pointers to
objects is destroyed. Should the objects be deleted (the container owns the
objects), or left alone (the container does not own the objects)? The
dangling reference problem would appear if you inserted an object into a
container, then destroyed the object (e.g. the object is a local variable
that went out of scope).

If you wish to create the equivalent of a container which contains pointers
to objects - replace std::vector<foo> with std::vector<foo *>.


Daniel Pfeffer


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Michiel Salters <salters@lucent.com>
Date: 2000/07/20
Raw View
Hicham BOUHMADI wrote:

> Hi.
> By using the STL and especially the STL containers, I found that it is
> designed so it only uses by value variables.
> This is why when instanciating a vector with a "big" type, it makes thing
> very slow...
> The solution I found is to use smart pointers.
> Depending on what it is intended, you can use auto_ptr, or a custom smart
> pointer that can also handle "garbage collection".
> The choice of the smart pointer depends on when the contained objects must
> be destructed.

You can't use auto_ptr<>, it doesn't have the required semantics to be stored
in a std::vector<>. In particular, std::vector<T> requires T::T(const T&) while
auto_ptr only has auto_ptr::auto_ptr(auto_ptr&), i.e. a non-const copy ctor.

Either use a custom smart pointer - e.g. reference counted - or contain a vector
of T* in a custom container. Still, if during insertion you are being passed
an big object with no further information, you do not know if you can just
store a pointer to it. What if you're passed a temporary? You should copy it in
that case.

That's of course why the STL always copies. You can insert(T()) a default T
in them.

Michiel Salters

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: brianjparker@ozemail.com.au (Brian Parker)
Date: 2000/07/20
Raw View
On Mon, 17 Jul 2000 03:10:54 CST, "Stefan Reiss" <stefan@reisz.de>
wrote:

>Hi.
>The vector template might become slow, if its element type has a non-trivial
>copy semantic.
>such as vector<vector<int> > . On each reallocation the elements must be
>copied, which means allocating memory and copying many elements. (i think
>there is no normal way for a compiler to optimize this away. I heard about a
>rule that if you call a copy-ctor and then a dtor with the same object, the
>compiler can optimize, but I think that wont help here.)
>
>But the inner copies could be avoided, if there were a special function , a
>"transfer-ctor" , which only redirects the pointers, like in std::swap.
>The transfer-ctor  T(T&t , transfer_t dummy) { ...} assures that afterwards
>, the new object is like the passed t, and t may be in any valid state (so
>dtor for t might be called later).
>
>I designed a fast_vector with such a transfer-ctor , and modified insert.
>
>The following code took
>  7 seconds with vector
>  1 second  with fast_vector
>
> vect<int> v(1000);
> vect<vect<int> >vv;
> for (int i = 0; i < 10000; ++i)   vv.push_back(v);
>
>it requires only little extension for <vector> and <memory>
>So it might be a good idea for a next standard

Hi,

I am a little unclear about this approach- could you provide a more
complete code sample?

Could you clarify which copy is avoided by your optimised copy
constructor? Does v get destroyed after vv.push_back(v), in which case
only the first push_back adds a 1000 element vector and the other 999
calls just add an empty vector?

In a similar situation I have used a little utility function as
follows-

template<typename C, typename T>
void push_back_destructive(C& c, T& t)
{
 c.push_back(T());
 stl::swap(c.back(), t);
}

After a call of push_back_destructive() the passed in object is
destroyed but a fast swap-based copy is made.

So, a similar  example to yours would become-

 vect<vect<int> >vv;
 for (int i = 0; i < 10000; ++i) {
   vect<int> v(1000);
   push_back_destructive(vv, v);
}

or alternatively you could write something like-

 vect<vect<int> >vv;
 for (int i = 0; i < 10000; ++i) {
   vect<int>& r = vv.push_back( vect<int>()).back();
 // initialise r directly here
 // ....
}

,Brian Parker
(brianp@research.canon.com.au)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Hicham BOUHMADI" <hicham@citeweb.net>
Date: 2000/07/20
Raw View
Hi.
You're right with auto_ptr. I used to use my smart pointers that also
handles garbage collection...
But when writing the msg, I thought about auto_ptr, and said that it should
be easier to use auto_ptr than a kind of smart pointers. My "quick" thought
was wrong... Sorry!! :p

Michiel Salters <salters@lucent.com> a    crit dans le message :
397548C8.C453ABD8@lucent.com...
> Hicham BOUHMADI wrote:
>
> > Hi.
> > By using the STL and especially the STL containers, I found that it is
> > designed so it only uses by value variables.
> > This is why when instanciating a vector with a "big" type, it makes
thing
> > very slow...
> > The solution I found is to use smart pointers.
> > Depending on what it is intended, you can use auto_ptr, or a custom
smart
> > pointer that can also handle "garbage collection".
> > The choice of the smart pointer depends on when the contained objects
must
> > be destructed.
>
> You can't use auto_ptr<>, it doesn't have the required semantics to be
stored
> in a std::vector<>. In particular, std::vector<T> requires T::T(const T&)
while
> auto_ptr only has auto_ptr::auto_ptr(auto_ptr&), i.e. a non-const copy
ctor.
>
> Either use a custom smart pointer - e.g. reference counted - or contain a
vector
> of T* in a custom container. Still, if during insertion you are being
passed
> an big object with no further information, you do not know if you can just
> store a pointer to it. What if you're passed a temporary? You should copy
it in
> that case.
>
> That's of course why the STL always copies. You can insert(T()) a default
T
> in them.
>
> Michiel Salters
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
>


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Stefan Reiss" <stefan@reisz.de>
Date: 2000/07/17
Raw View
Hi.
The vector template might become slow, if its element type has a non-trivial
copy semantic.
such as vector<vector<int> > . On each reallocation the elements must be
copied, which means allocating memory and copying many elements. (i think
there is no normal way for a compiler to optimize this away. I heard about a
rule that if you call a copy-ctor and then a dtor with the same object, the
compiler can optimize, but I think that wont help here.)

But the inner copies could be avoided, if there were a special function , a
"transfer-ctor" , which only redirects the pointers, like in std::swap.
The transfer-ctor  T(T&t , transfer_t dummy) { ...} assures that afterwards
, the new object is like the passed t, and t may be in any valid state (so
dtor for t might be called later).

I designed a fast_vector with such a transfer-ctor , and modified insert.

The following code took
  7 seconds with vector
  1 second  with fast_vector

 vect<int> v(1000);
 vect<vect<int> >vv;
 for (int i = 0; i < 10000; ++i)   vv.push_back(v);

it requires only little extension for <vector> and <memory>
So it might be a good idea for a next standard

Stefan



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Sergey P. Derevyago" <ders.NOS@skeptik.net>
Date: 2000/07/18
Raw View
Stefan Reiss wrote:
> But the inner copies could be avoided, if there were a special function , a
> "transfer-ctor" , which only redirects the pointers, like in std::swap.
> The transfer-ctor  T(T&t , transfer_t dummy) { ...} assures that afterwards
> , the new object is like the passed t, and t may be in any valid state (so
> dtor for t might be called later).
 I think that STL should widely use std::move() template just like it use
std::swap() now (even std::swap() can be easily expressed via std::swap()).
Also this can clean up a lot of problems with STL exception safety because
std::move() is cheap and not allowed to throw any exceptions.
--
         With all respect, Sergey.          http://cpp3.virtualave.net/
         mailto : ders at skeptik.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]