Topic: -1?Q?Re: Request f r std::vector and possibly others: mi


Author: Jason McKesson<jmckesson@gmail.com>
Date: Wed, 21 Mar 2012 11:35:35 -0700 (PDT)
Raw View
On Monday, March 19, 2012 11:35:35 PM UTC-7, henrikv wrote:
>  Hello group!
>
>  When writing parallel code, I often allocate a vector for results. I
>  allocate the complete vector with a single resize. What I'd like to do
>  is to tell the resize not to initialize the content, since this will
>  be overwritten anyway. I'd figure something like:
>
>  struct no_init {} g_no_int;
>
>  struct Dummy
>  {
>   Dummy(int a_=0) : a(a_) {}
>   Dummy(const no_init&) {} // Without a v-table, this shouldn't need
>  to
>  touch any part of the created object?
>
>   int a;
>  };
>
>  void foo()
>  {
>   std::vector<Dummy>  dummies;
>   dummies.resize(1000, g_no_int);
>   // ...
>  }
>
>  Proposal: add a method to std::vector that allows resize with a
>  different constructor than default or copy
>  constructor:
>
>                 template<typename T2>
>                 void resize_construct_using_translation(size_t n, const T2&t2);
>
>  Any thoughts on this?
>
>  Best regards,
>  Henrik Vallgren
>

This looks more like an improper use of `std::vector` than anything that should be added to the specification.

All you need to do is use `std::vector::reserve` to allocate as much space as you plan to use. Then use `emplace_back` to construct each addition to the `vector` in-place.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: henrikv<henrik.vallgren@stream-space.com>
Date: Fri, 23 Mar 2012 17:09:57 -0700 (PDT)
Raw View
On 21 mar, 19:35, Francis
Glassborow<francis.glassbo...@btinternet.com>  wrote:
>  Isn't that what reserve() is for?

What I want to do is to allocate a vector for results calculated in a
parallel loop. Reserve+push_back will not work, since it's not
guaranteed that results will be stored in a predictable order. You
might even get multiple push_back's executed at once, which I suspect
isn't a great idea.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: henrikv<henrik.vallgren@stream-space.com>
Date: Fri, 23 Mar 2012 17:10:25 -0700 (PDT)
Raw View
On 21 mar, 19:35, Jason McKesson<jmckes...@gmail.com>  wrote:
>  This looks more like an improper use of `std::vector` than anything that should be added to the specification.

IMO, telling the vector which constructor to use isn't "improper use".
I'm trying to achieve "minimal but proper initialization", so a class
containing something like a std::string would require that member to
be properly initialized. I can do the same thing today, all that's
required is a default constructor that doesn't touch anything that's
not required:

struct NoInitDummy
{
   NoInitDummy() {}

   // Make this behave like a Dummy using conversion operators etc
   int a;
};

>  All you need to do is use `std::vector::reserve` to allocate as much space as you plan to use. Then use `emplace_back` to construct each addition to the `vector` in-place.

Using reserve+emplace_back isn't a good idea. I'm thinking *parallel*
loop here, so neither order, nor race conditions can be predicted.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Kevin McCarty<kmccarty@gmail.com>
Date: Fri, 23 Mar 2012 17:11:22 -0700 (PDT)
Raw View
On Mar 21, 11:35 am, Jason McKesson<jmckes...@gmail.com>  wrote:
>  On Monday, March 19, 2012 11:35:35 PM UTC-7, henrikv wrote:
>  >    Hello group!
>
>  >    When writing parallel code, I often allocate a vector for results. I
>  >    allocate the complete vector with a single resize. What I'd like to do
>  >    is to tell the resize not to initialize the content, since this will
>  >    be overwritten anyway. I'd figure something like:
[snip]
>  >    Any thoughts on this?

>  This looks more like an improper use of `std::vector` than anything that should be added to the specification.
>
>  All you need to do is use `std::vector::reserve` to allocate as much space as you plan to use. Then use `emplace_back` to construct each addition to the `vector` in-place.


There are at least two situations I can think of, where it would be
*very* useful to be able to initialize or resize a vector of PODs such
that the newly allocated elements will have no initialization
performed.  (I'm ambivalent as to the exact mechanics Henrik
proposed.)


Case 1)  Interfacing with old (C?) code that will initialize a
contiguous block of memory in-place.  One can't always expect that
existing code can be rewritten to take a vector and call push_back or
emplace_back on it.

E.g., supposing the existence of something called std::no_initialize
(whatever that might be)

// some old 3rd-party library function; maybe it calls fread()?
extern "C" initialize_mem(size_t sz, int * mem);

vector<int>  ints(42, std::no_initialize);
initialize_mem(ints.size(), ints.data());


Case 2) When it is necessary (or at least, easiest) to initialize the
elements in an order other than the consecutive forward traversal you
get with repeated calls to push_back or emplace_back.  Consider
setting up a reverse look-up table for instance:

void make_reverse_lookup(const vector<int>  &  lut, vector<int>  &
revlut)
{
     // Pre-condition: the contents of 'lut' are the integers
     // 0 through lut.size() - 1 in some arbitrary order.
     int n = lut.size();
     revlut.resize(n, std::no_initialize);

     for (int i = 0; i<  n; ++i)
         revlut[lut[i]] = i;
}


- Kevin B. McCarty


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Jason McKesson<jmckesson@gmail.com>
Date: Sat, 24 Mar 2012 17:55:01 -0700 (PDT)
Raw View
On Friday, March 23, 2012 5:10:25 PM UTC-7, henrikv wrote:
>  On 21 mar, 19:35, Jason McKesson<jmckes...@gmail.com>   wrote:
>  >   This looks more like an improper use of `std::vector` than anything that should be added to the specification.
>
>  IMO, telling the vector which constructor to use isn't "improper use".
>  I'm trying to achieve "minimal but proper initialization", so a class
>  containing something like a std::string would require that member to
>  be properly initialized. I can do the same thing today, all that's
>  required is a default constructor that doesn't touch anything that's
>  not required:
>
>  struct NoInitDummy
>  {
>     NoInitDummy() {}
>
>     // Make this behave like a Dummy using conversion operators etc
>     int a;
>  };

How "minimal" do you want? `std::vector::resize(size_t n)` will value-initialize each element. Why do you need it to be *default* initialized?

>  >   All you need to do is use `std::vector::reserve` to allocate as much space as you plan to use. Then use `emplace_back` to construct each addition to the `vector` in-place.
>
>  Using reserve+emplace_back isn't a good idea. I'm thinking *parallel*
>  loop here, so neither order, nor race conditions can be predicted.

I didn't say to use `emplace_back` as part of the parallel loop. I meant that you would do that to *initialize* the `vector`, using exactly the constructor you want.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Jason McKesson <jmckesson@gmail.com>
Date: Sat, 24 Mar 2012 19:27:45 -0700 (PDT)
Raw View
On Friday, March 23, 2012 5:11:22 PM UTC-7, Kevin McCarty wrote:
> On Mar 21, 11:35 am, Jason McKesson<jmckes...@gmail.com>  wrote:
> >  On Monday, March 19, 2012 11:35:35 PM UTC-7, henrikv wrote:
> >  >    Hello group!
> >
> >  >    When writing parallel code, I often allocate a vector for results. I
> >  >    allocate the complete vector with a single resize. What I'd like to do
> >  >    is to tell the resize not to initialize the content, since this will
> >  >    be overwritten anyway. I'd figure something like:
> [snip]
> >  >    Any thoughts on this?
>
> >  This looks more like an improper use of `std::vector` than anything that should be added to the specification.
> >
> >  All you need to do is use `std::vector::reserve` to allocate as much space as you plan to use. Then use `emplace_back` to construct each addition to the `vector` in-place.
>
>
> There are at least two situations I can think of, where it would be
> *very* useful to be able to initialize or resize a vector of PODs such
> that the newly allocated elements will have no initialization
> performed.  (I'm ambivalent as to the exact mechanics Henrik
> proposed.)

Objects cannot have "no initialization performed" on them. An object
either exists (and therefore has been initialized) or it doesn't (and
thus isn't an object; it's a block of memory).

Since you mentioned PODs (more accurately, trivial types), you seem to
be talking about the performance difference between default
initialization (ie: contains undefined stuff) and value initialization
(ie: zeroed out, more or less).

So, at the very least, you would want to call it this:

 vector<int>  ints(42, std::default_init);

Personally, it's something so minor that I wouldn't really bother with
it. But at the same time, it could be an issue in performance critical
code.

Of course, you still need to solve this problem:

 std::vector<decltype(std::default_init)> stuff(42, std::default_init);

Which constructor gets called?


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: henrikv <henrik.vallgren@stream-space.com>
Date: Sun, 25 Mar 2012 23:14:29 -0700 (PDT)
Raw View
On 25 mar, 02:55, Miles Bader<mi...@gnu.org> wrote:
> Agreed, this would be a nice feature to have.
>
> It's obviously a more dangerous operation than most, so a suitably
> scary name ("resize_uninitialized_yes_yes_I_know_what_Im_doing")
> might be called for...
>
> Right now, I just use a wrapper class for the stored element type to
> achieve this effect, but that's less flexible and can be awkward.
>
> -Miles

Great idea! So one could use:

template <typename T>
struct MinimalConstructible : public T
{
   MinimalConstructible() : T(std::use_minimal_initialization) {}
};

//...
std::vector<MinimalConstructible<Dummy> >   data;

Henrik


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: jgk@panix.com (Joe keane)
Date: Tue, 27 Mar 2012 12:10:06 -0700 (PDT)
Raw View
In article<b94ffa35-1289-4a00-b9fd-92a56dfee459@w32g2000vbt.googlegroups.com>,
henrikv<henrik.vallgren@stream-space.com>  wrote:
>struct NoInitDummy
>{
>    NoInitDummy() {}
>
>    // Make this behave like a Dummy using conversion operators etc
>    int a;
>};

C++ gives some rules about when things get initialized, which usually
helps you, but sometimes just gets in your way.  So then you think, 'you
want the one function to run but not the other one?' and then you're
like 'umm, -yeah-, that's what i want'.  So then you think, 'is my
design defective?', or is this a case where C++ has inferred what
behavior you want, when actually that is not the behavior you want.

An example is class Y derives from class X.  The way to initialize Y, so
we are told, is to call a function to initialize it so far as being an X
object, then call another function to convert an X object to a Y object.
Sometimes this is awkward.  Sometimes the easiest thing to do is to say
'the Y initializer will do everything, and please don't talk to the X
initializer at all'.  I don't think that is bad design, it's just where
some of the tacit assumptions in the language go a bit awkward; it's not
saying you *can't* do that, that's what an 'uninit' class is there for.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: =?ISO-8859-1?Q?Pedro_Lamar=E3o?=<pedro.lamarao@gmail.com>
Date: Thu, 29 Mar 2012 12:28:07 -0700 (PDT)
Raw View
Em sexta-feira, 23 de mar   o de 2012 21h11min22s UTC-3, Kevin McCarty  escreveu:

>  Case 1)  Interfacing with old (C?) code that will initialize a
>  contiguous block of memory in-place.  One can't always expect that
>  existing code can be rewritten to take a vector and call push_back or
>  emplace_back on it.
>
>  E.g., supposing the existence of something called std::no_initialize
>  (whatever that might be)
>
>  // some old 3rd-party library function; maybe it calls fread()?
>  extern "C" initialize_mem(size_t sz, int * mem);
>
>  vector<int>   ints(42, std::no_initialize);
>  initialize_mem(ints.size(), ints.data());

In the OP's use case, there is a known amount of "results" for which space must be allocated.

And it is desired to have space allocated, but no constructors run on it.

Isn't uninitialized-land where operator new and std::allocator live? Why not go there?

--
  P.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]