Является ли это возможным? std::vector <double> my_vec (sz); который выделяется, но не инициализируется или не заполняется

В [Объектах с инициализацией значения в конструкторе С++ 11 и std::vector Channel72 спрашивает,

Вопрос: Является ли мое понимание правильным здесь? Является ли явный std::vector (size_type count) неинициализированным массивом (аналогично malloc), если T является POD?

Ответ - нет.

Мой вопрос: "Ладно, что?"

Один из ответов, написанный Невином, подсказывает мне ответить на мой вопрос. Чтобы уточнить, мой вопрос: Есть ли способ использовать std::vector <double> без его бесплатного заполнения выделенной памяти нулями или чем-то еще?

Я не прошу обходных решений, например, запускает вектор с нулевым размером и использует push_back(). Это не всегда возможно, и, кроме того, на этом этапе я хочу, чтобы это выяснилось не по какой-либо другой причине, чем я хочу понять.

Я не могу получить предложение Nevin, пользовательский распределитель, для компиляции. VС++ 2017rc (Dinkum) жалуется своим обычным непостижимым способом. Что-то о std:: _ Wrap_alloc. Код Невина является неполным, и я, вероятно, не знаю, как его завершить. Прежде чем я увидел его, я написал свой собственный распределитель, который, похоже, работает, но я не уверен в своем понимании, чтобы поклясться в этом.

В то время, когда я размышлял над этим, я мог бы написать менее догматическую замену std::vector, а также несколько глав Великого американского романа.

Ответ 1

УРА! Ричард Критт на помощь! Его комментарий по вопросу приводит непосредственно к ответу.

Ликвидатор с нулевым извержением является шаблоном распределителя по умолчанию, а именно std:: allocator. Поэтому мы заменяем его или модифицируем его с помощью адаптера распределителя.

Я немного прибрал код и расширил комментарии. Билл, не стесняйтесь публиковать более полный ответ. Но вот что делает трюк очень хорошо.

// Allocator adapter
// Given an allocator A, (std::allocator by default), this adapter 
// will, when feasible, override A::construct() with a version that 
// employs default construction rather than value-initialization.
// "Feasible" means the object (U *ptr) is default-constructable and
// the default constructor cannot throw exceptions.
// 
// Thus it thwarts gratuitous initializations to zeros or whatever.

template <typename T, typename A = std::allocator<T>>
class default_init_allocator : public A {
    typedef std::allocator_traits<A> a_t;
public:
    // http://en.cppreference.com/w/cpp/language/using_declaration
    using A::A; // Inherit constructors from A

    template <typename U> struct rebind {
        using other =
            default_init_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

Не пробовал это, но из какого-то googling можно сделать это, предоставив пользовательский Allocator std::vector. См. Последнюю строку из http://en.cppreference.com/w/cpp/concept/DefaultInsertable

Если инициализация значения нежелательна, например, если объект имеет тип неклассов и обнуление не требуется, его можно избежать, предоставив пользовательскую конструкцию Allocator:: construct

Ответ 3

Вы можете инициализировать вектор с массивом с выделенной памятью.

Type* typeArray = new Type [size];
vector <Type> typeVec (typeArray, typeArray+size);

Это даст вам выделенную память (это будет мусор, хотя), и вам придется быть осторожным в доступе к этому, потому что это позволит вам позвонить   typeVec [n].typeVal и это, скорее всего, приведет к поведению undefined, если вы фактически не инициализировали значение при n

Или, если Type был неклассовым типом, значение в n было бы просто значением того, что осталось там