2012-06-11 5 views
3

Например, почему не template< typename Elem, typename Traits, typename Alloc > basic_string { ... } обеспечивают:Почему не СТД типа обеспечивают преобразование конструктор/назначения из источников отличаясь распределителем

template< typename OtherAlloc > 
basic_string(const basic_string< Elem, Traits, OtherAlloc >& a_Other) { ... } 

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

+1

Возможно, было бы непросто реализовать функцию шаблона, которая преобразует типы шаблонов std, которые отличаются только их распределителем. (Я не говорю, что этот вопрос недействителен - это, конечно же, - только то, что количество кода, необходимого для работы вокруг этого, не должно быть много.) – cdhowie

+0

Да, поскольку преобразование не может быть свободным оператором I я должен явно преобразовать всю свою кодовую базу, но все равно может быть единственным решением :( – Ylisar

+0

Да, автоматическое преобразование будет невозможно, к сожалению. – cdhowie

ответ

3

Стандартный хеш также не позволяет распределителю fun- it can hash std::string и std::wstring, но не std::basic_string<char, std::char_traits<char>, custom_alloc>. Кроме того, вы не можете создать unordered_map или unordered_set с помощью только распределителя - вы также должны указать номер ведра, который по умолчанию соответствует константе, определенной для реализации, к которой вы не можете получить доступ, поэтому вы должны просто что-то сделать. Поддержка, как правило, не очень хороша.

Мне кажется, что относительно просто никто не предлагал такую ​​функцию или не изучал это пространство использования.

+0

Трудно поверить, придумывайте при работе с 'tuple' и' pair' и т. д., там _has_, чтобы быть причиной этого. :( –

+0

@MooingDuck: Что делают 'tuple' и' pair' связаны с распределителями? И многие упущения i n стандарт случается, потому что никто не предлагал их; почему это было бы иначе? –

+0

@NicolBolas: Вы можете построить 'tuple' и' pair' из 'tuple' /' pair', содержащего разные типы _including другого allocator type_, и он работает почти точно_ так, как запросит OP. Если 'tuple' /' pair' почти делают это, почему бы не «настоящие» контейнеры? (C++ 11 Jan2012 §20.4.2.1/26) –

1

Проблема намного сложнее, чем кажется. Поскольку тип распределителя является частью типа объекта, допускается малое взаимодействие между типами, которые отличаются только распределителем. Первый пример, который приходит на ум, состоит в том, что функция, которая принимает значение std::string по постоянной ссылке, не может принимать строку, которая использует другой распределитель. Один из таких случаев - при строительстве объектов. На самом деле это, наверное, сложнее.

Рассмотрим, например, следующий код:

// Assume that you could construct from a different allocator 
std::vector<int, allocator1> f() { 
    std::vector<int, allocator2> r; 
    // fill in 
    return r; 
} 
int main() { 
    std::vector<int, allocator3> x = f(); 
} 

Считают, что это allocator1std::allocator<int> (т.е. Распределитель по умолчанию), что allocator2 использует локальную арену в стеке, и что allocator3 может использовать совместно используемую память. Теоретически код достаточно прост, вектор r создается и заполняется данными, заявление возвращения нового временного создается копирования из r, и, наконец, x строится копирования от временного. Проблема в том, что стандарт позволяет (и компиляторам) избегать копирования в максимально возможной степени. В приведенном выше примере (и игнорировании распределителей) компилятор будет лидировать в обеих копиях и создавать буфер только один раз, что является быстрым и эффективным. Но при том, что распределители потенциально могут быть разными, NRVO и другие типы copy-elision должны быть отключены. (Если эти оптимизации включены, x в основном будет использовать allocator2, с локальной ареной, которая уже была уничтожена, что вызвало неопределенное поведение).

Включая построение копии из контейнеров с одним распределителем в другой, вы можете оказаться в беспорядке или в более глубоком беспорядке, чем мы уже находимся в текущем стандарте, где вы можете вызвать всевозможные интересные проблемы с помощью генераторов с поддержкой состояния (скажем, что вы используете распределяющие потоки, и что вы вносите данные в общую очередь, вы можете получить один поток, содержащий объект, созданный распределителем потоков для другого потока, и потому, что точка использования per- нить распределители, избегают раздоров на замках, вы могли бы создать условия гонки по-видимому, безопасный код ....


Это старый р создание комитета C++ Towards a better allocation model, что вызывает некоторые проблемы с моделью распределения C++ 03 и предлагает тип полиморфного распределителя (который имеет проблемы с его собственными).Это делает интересным чтение, но остерегайтесь деталей, не все так хорошо, как кажется, и есть немало ошибок в использовании любой опции (или версии C++ 11, которая похожа на C++ 03 версия)

+1

Yupp, нет NRVO в случае, когда распределители отличаются. Я понимаю, что любое перемещение данных строго запрещено, когда распределители не совпадают, но мне кажется, что было бы довольно просто воспользоваться лучшим случаем, когда распределители будут соответствовать из-за лучших правил специализации. – Ylisar

+0

@Ylisar: Проблема в том, что компилятор не может знать, совпадают ли распределители во втором копировании. То есть вызывающий выделяет пространство для объекта в его контексте, а затем вызывает функцию. Эта функция может вывести копию из 'r' в оператор return, но не может знать, является ли распределитель в контексте вызывающего абонента одинаковым или совместимым. Также обратите внимание, что это сложнее отслеживать, чем выглядит. Как вы знаете (без фактического знания о реализации распределителя), можно ли повторно использовать распределитель или нет? –

+0

@MooingDuck: вы пропустили то, что до последнего абзаца является гипотетическим предположением, что предположение о том, что копирование конструкции из другого типа распределителя было разрешено. То есть, если то, о чем спрашивает Q., было разрешено, чтобы вы столкнулись с перечисленными выше проблемами, а это значит, что либо вы отключите все копии для всех типов, у которых есть распределитель, либо вы стучите по краю бритвы ... –