c++ - How can I avoid std::vector<> to initialize all its elements? -


edit: edited both question , title more precise.

considering following source code:

#include <vector> struct xyz {     xyz() { } // empty constructor, compiler doesn't care     xyz(const xyz& o): v(o.v) { }      xyz& operator=(const xyz& o) { v=o.v; return *this; }     int v; // <will initialized int(), means 0 };  std::vector<xyz> test() {     return std::vector<xyz>(1024); // memset() :-( } 

...how can avoid memory allocated vector<> initialized copies of first element, o(n) operation i'd rather skip sake of speed, since default constructor nothing ?

a g++ specific solution do, if no generic 1 exists (but couldn't find attribute that).

edit: generated code follows (command line: arm-elf-g++-4.5 -o3 -s -fno-verbose-asm -o - test.cpp | arm-elf-c++filt | grep -ve '^[[:space:]]+[.@].*$' )

test():     mov r3, #0     stmfd   sp!, {r4, lr}     mov r4, r0     str r3, [r0, #0]     str r3, [r0, #4]     str r3, [r0, #8]     mov r0, #4096     bl  operator new(unsigned long)     add r1, r0, #4096     add r2, r0, #4080     str r0, [r4, #0]     stmib   r4, {r0, r1}     add r2, r2, #12     b       .l4          @ .l8:                     @     add     r0, r0, #4   @ .l4:                     @     cmp     r0, #0       @  fill memory     movne   r3, #0       @     strne   r3, [r0, #0] @     cmp     r0, r2       @     bne     .l8          @     str r1, [r4, #4]     mov r0, r4     ldmfd   sp!, {r4, pc} 

edit: sake of completeness, here assembly x86_64:

.globl test() test(): lfb450:     pushq   %rbp lcfi0:     movq    %rsp, %rbp lcfi1:     pushq   %rbx lcfi2:     movq    %rdi, %rbx     subq    $8, %rsp lcfi3:     movq    $0, (%rdi)     movq    $0, 8(%rdi)     movq    $0, 16(%rdi)     movl    $4096, %edi     call    operator new(unsigned long)     leaq    4096(%rax), %rcx     movq    %rax, (%rbx)     movq    %rax, 8(%rbx)     leaq    4092(%rax), %rdx     movq    %rcx, 16(%rbx)     jmp     l4          @ l8:                     @     addq    $4, %rax    @ l4:                     @     testq   %rax, %rax  @ memory-filling loop     je      l2          @     movl    $0, (%rax)  @ l2:                     @     cmpq    %rdx, %rax  @     jne     l8          @     movq    %rcx, 8(%rbx)     movq    %rbx, %rax     addq    $8, %rsp     popq    %rbx     leave lcfi4:     ret lfe450: eh_frame1: lscie1: lecie1: lsfde1: lasfde1: lefde1: 

edit: think conclusion not use std::vector<> when want avoid unneeded initialization. ended unrolling own templated container, performs better (and has specialized versions neon , armv7).

the initialization of elements allocated controlled allocator template argument, if need customized, customize it. remember can wind-up in realm of dirty hacking, use caution. instance, here pretty dirty solution. avoid initialization, worse in performance, demonstration's sake (as people have said impossible!... impossible not in c++ programmer's vocabulary!):

template <typename t> class switch_init_allocator : public std::allocator< t > {   private:     bool* should_init;   public:     template <typename u>     struct rebind {       typedef switch_init_allocator<u> other;     };      //provide required no-throw constructors / destructors:     switch_init_allocator(bool* ashouldinit = null) throw() : std::allocator<t>(), should_init(ashouldinit) { };     switch_init_allocator(const switch_init_allocator<t>& rhs) throw() : std::allocator<t>(rhs), should_init(rhs.should_init) { };     template <typename u>     switch_init_allocator(const switch_init_allocator<u>& rhs, bool* ashouldinit = null) throw() : std::allocator<t>(rhs), should_init(ashouldinit) { };     ~switch_init_allocator() throw() { };      //import required typedefs:     typedef typename std::allocator<t>::value_type value_type;     typedef typename std::allocator<t>::pointer pointer;     typedef typename std::allocator<t>::reference reference;     typedef typename std::allocator<t>::const_pointer const_pointer;     typedef typename std::allocator<t>::const_reference const_reference;     typedef typename std::allocator<t>::size_type size_type;     typedef typename std::allocator<t>::difference_type difference_type;      //redefine construct function (hiding base-class version):     void construct( pointer p, const_reference cr) {       if((should_init) && (*should_init))         new ((void*)p) t ( cr );       //else, nothing.     }; };  template <typename t> class my_vector : public std::vector<t, switch_init_allocator<t> > {   public:     typedef std::vector<t, switch_init_allocator<t> > base_type;     typedef switch_init_allocator<t> allocator_type;     typedef std::vector<t, allocator_type > vector_type;     typedef typename base_type::size_type size_type;   private:     bool switch_flag; //the order here important!!     vector_type vec;   public:       my_vector(size_type acount) : switch_flag(false), vec(acount, allocator_type(&switch_flag)) { };     //... , rest of wrapper class...     vector_type& get_vector() { return vec; };     const vector_type& get_vector() const { return vec; };     void set_switch(bool value) { switch_flag = value; }; };  class xyz{};  int main(){   my_vector<xyz> v(1024); //this won't initialize memory @ all.   v.set_switch(true); //set true turn initialization on (needed resizing , such) } 

of course, above awkward , not recommended, , won't better letting memory filled copies of first element (especially since use of flag-checking impede on each element-construction). avenue explore when looking optimize allocation , initialization of elements in stl container, wanted show it. point place can inject code stop std::vector container calling copy-constructor initialize elements in construct function of vector's allocator object.

also, away "switch" , "no-init-allocator", then, turn off copy-construction needed copy data during resizing (which make vector class less useful).


Comments

Popular posts from this blog

c# - how to write client side events functions for the combobox items -

exception - Python, pyPdf OCR error: pyPdf.utils.PdfReadError: EOF marker not found -