Why does C ++ initialize std :: vector with zeros but not std :: array?

Isn't it a waste of time to initialize a vector with zeros when you don't want it?

I am trying this code:

#include <iostream>
#include <vector>
#include <array>

#define SIZE 10

int main()
{
#ifdef VECTOR

  std::vector<unsigned> arr(SIZE);

#else

  std::array<unsigned, SIZE> arr;

#endif // VECTOR

  for (unsigned n : arr)
    printf("%i ", n);
  printf("\n");

  return 0;
}

and I get the output:

with vector

$ g++ -std=c++11 -D VECTOR test.cpp -o test && ./test 
0 0 0 0 0 0 0 0 0 0 

with an array

g++ -std=c++11  test.cpp -o test && ./test 
-129655920 32766 4196167 0 2 0 4196349 0 1136 0 

And I'm also trying to use clang ++

So why are zeros? And by the way, can I declare a vector without initializing it?

+4
source share
3 answers

Suppose we have some class:

class MyClass {
    int value;

public:
    MyClass() {
        value = 42;
    }
    // other code
};

std::vector<MyClass> arr(10);will build 10 copies by default MyClass, all with value = 42.

, 10 . , arr[0].some_function(), : MyClass , . some_function(), value == 42, , value . .

++ . , . std::vector<MyClass> arr(10); , .

, std::array , . , std::array<MyClass, 10> arr; 10 MyClass value = 42. , unsigned, .


: std::vector::reserve. :

std::vector<MyClass> arr;
arr.reserve(10);

10 MyClass s, . arr[0] arr[5]; arr (arr.size() - 0, ). , push_back emplace_back:

arr.push_back(MyClass{});

. , arr std::rand, std::generate_n std::back_inserter:

std::vector<unsigned> arr;
arr.reserve(10);
std::generate_n(std::back_inserter(arr), 10, std::rand);

, , arr , begin()/end() :

std::vector<unsigned> arr{values.begin(), values.end()};
+1

- :

std::vector<unsigned> arr;

. , .push_back(). , reserve():

arr.reserve(SIZE);

, size() , - undefined.

arr.resize(SIZE);

.

std::array, , . , C-, . .

+4

The dispenser defaults to zero initialization. You can use another dispenser that does not. I wrote a dispenser that, by default, uses the default construct, not initialization. More precisely, this is a distribution shell called ctor_allocator. Then I define a template vector.

dj:vector<unsigned> vec(10);does exactly what you want. It is a std::vector<unsigned> (10)that is not initialized to zeros.

--- libdj/vector.h ----
#include <libdj/allocator.h>
#include <vector>

namespace dj {
template<class T>
    using vector = std::vector<T, dj::ctor_allocator<T>>;
}

--- libdj/allocator.h  ----
#include <memory>

namespace dj {

template <typename T, typename A = std::allocator<T>>
    class ctor_allocator : public A 
    {
        using a_t = std::allocator_traits<A>;
    public:
        using A::A; // Inherit constructors from A

        template <typename U> struct rebind 
        {
            using other =
                ctor_allocator
                <  U, typename a_t::template rebind_alloc<U>  >;
        };

        template <typename U>
        void construct(U* ptr)
            noexcept(std::is_nothrow_default_constructible<U>::value) 
        {
            ::new(static_cast<void*>(ptr)) U;
        }

        template <typename U, typename...Args>
        void construct(U* ptr, Args&&... args) 
        {
            a_t::construct(static_cast<A&>(*this),
                ptr, std::forward<Args>(args)...);
        }
    };
}
+2
source

Source: https://habr.com/ru/post/1693598/


All Articles