2016-11-18 4 views
5

Эта тема возникла в этой теме об изменении в StD :: Список :: Sort() для Visual Studio 2015:Как создать конструктор C++ 11, не имеющий значения по умолчанию?

`std::list<>::sort()` - why the sudden switch to top-down strategy?

Новая версия станд :: :: Список сортировки не требуется стандартный конструктивный std :: list, поскольку он использует только итераторы и не создает никаких локальных списков, поэтому не имеет значения, нельзя ли по умолчанию создавать списки. До версии используется локальные списки (примечание - каждый экземпляр списка включает в себя динамическое выделение узла дозорного):

typedef list<_Ty, _Alloc> _Myt; 
    // ... 
    const size_t _MAXBINS = 25; 
    _Myt _Templist, _Binlist[_MAXBINS]; 

Я пытаюсь создать конструктивизируемый список не по умолчанию, с Visual Studio 2015 версии для проверьте, как это происходит при изменении в std :: list :: sort().

Сначала я пробовал пример минимального распределителя Microsoft C++ 11. udpate - мне пришлось изменить одну строку для того, чтобы ответ Джонатана Wakely на работу и продемонстрировать вопрос:

template <class T> 
struct Mallocator 
{ 
    typedef T value_type; 
// Mallocator() noexcept {} // replaced this line from the Microsoft example 
    Mallocator(T) noexcept {} // no default constructor 

    // A converting copy constructor: 
    template<class U> Mallocator(const Mallocator<U>&) noexcept {} 
    template<class U> bool operator==(const Mallocator<U>&) const noexcept 
    { 
     return true; 
    } 
    template<class U> bool operator!=(const Mallocator<U>&) const noexcept 
    { 
     return false; 
    } 
    T* allocate(const size_t n) const; 
    void deallocate(T* const p, size_t) const noexcept; 
}; 

template <class T> 
T* Mallocator<T>::allocate(const size_t n) const 
{ 
    if (n == 0) 
    { 
     return nullptr; 
    } 
    if (n > static_cast<size_t>(-1)/sizeof(T)) 
    { 
     throw std::bad_array_new_length(); 
    } 
    void* const pv = malloc(n * sizeof(T)); 
    if (!pv) { throw std::bad_alloc(); } 
    return static_cast<T*>(pv); 
} 

template<class T> 
void Mallocator<T>::deallocate(T * const p, size_t) const noexcept 
{ 
    free(p); 
} 

обновление - с Mallocator изменен, чтобы иметь конструктор не по умолчанию, это сейчас приводит к ошибке компиляции :

typedef unsigned long long uint64_t; 
    std::list <uint64_t, Mallocator<uint64_t>> dll; // doubly linked list 

Используя предлагаемое изменение от Jonathan Wakely работает и воспроизводит вопрос, где старый станд :: список :: сортировать получает ошибку компиляции из-за локальные списки и показывает, что новый станд :: список :: сортировать без локальных списков работает без конструктора по умолчанию:

std::list<uint64_t, Mallocator<uint64_t>> dll(Mallocator<uint64_t>(0)); 

Я также попробовал этот метод, основанный на нитку здесь на SO:

struct Allocator { 
    void construct(void* p, const void* container) const {}; 
    void destruct(void* p, const void* container) const {}; 
}; 

void* operator new (size_t size, const Allocator& alloc, const void* container) 
{ 
    void* allocated_memory = std::malloc(size); 
    if (!allocated_memory) { 
     throw std::bad_alloc(); 
    } 

    alloc.construct(allocated_memory, container); 
    return allocated_memory; 
} 

void operator delete(void* p, const Allocator& alloc, const void* container) 
{ 
    alloc.destruct(p, container); 
    std::free(p); 
} 

В главном

typedef unsigned long long uint64_t; 
// ... 
    Allocator alloc; 
    std::list<uint64_t> *dll = new(alloc, NULL)std::list<uint64_t>; 
    // ... 
    operator delete(dll, alloc, NULL); 

, но это работает как для старых, так и новых версий станд :: list :: sort, поэтому он получает конструктор по умолчанию.

Итак, вопрос в том, как создать конструктор нестандартного распределения по умолчанию?

Благодаря демонстрации от Игоря Тандтни и ответа от Джонатана Вакли, я смог изменить вышеприведенный блок распределения Microsoft (отмеченный в комментариях), чтобы не иметь конструктор по умолчанию, и воспроизвести проблему, связанную со старым std: : список :: сортировать.

+1

Если аллокатор не по умолчанию, конструктивны, то а) вам необходимо предоставить некоторые другие средства, чтобы построить один, и б) вы должны передать экземпляр, построенный с помощью эти средства, в конструктор 'std :: list' (все его конструкторы принимают распределитель как необязательный последний параметр). –

+0

@IgorTandetnik - Проблема в том, как создать конструктор нестандартного распределения по умолчанию? – rcgldr

+3

Не указывайте ему конструктор по умолчанию и не пытайтесь его по умолчанию строить! –

ответ

5

Если вы по умолчанию построить std::list, то он будет по умолчанию, построить его аллокатор, так это определение переменного еще требует конструктора по умолчанию:

std::list <uint64_t, Mallocator<uint64_t>> dll; // doubly linked list 

Если вы хотите проверить распределители без конструкторов по умолчанию, что вам нужно сделать, это иначе

std::list <uint64_t, Mallocator<uint64_t>> dll(Mallocator<uint64_t>(args)); 

Или:

Mallocator<uint64_t> alloc(some, args, for, your, allocator); 
std::list <uint64_t, Mallocator<uint64_t>> dll(alloc); 
+1

Мне пришлось изменить одну строку из примера Microsoft (я обновил свой вопрос), чтобы отключить конструктор по умолчанию. Это позволило вашему методу проверить распределители без стандартных конструкторов. – rcgldr

+0

Я забыл спросить, почему кто-то хочет создать распределитель без конструктора по умолчанию, по крайней мере, в случае std :: list? Возможно, это имеет смысл для других типов контейнеров/объектов или специальных сред? – rcgldr

+0

Это так же справедливо для std :: list, как и все остальное. Не может быть разумного свойства по умолчанию для настраиваемого распределителя (например, размер начальной арены или сегмент разделяемой памяти для использования или файл журнала для записи информации о распределениях), поэтому для этого всегда требуется аргумент конструктора. Если вы хотите, чтобы std :: list использовал этот настраиваемый распределитель, вам необходимо предоставить аргумент. Такие вещи редко нужны, но это не значит, что они не имеют смысла. Обычно они нужны только для особых условий, поэтому вам не нужно терять сон. –

Смежные вопросы