Так вот вопрос, может я чего-то упустил, но я не могу найти плюсов у первого варианта по сравнению со вторым.
Вам какой больше нравится, что бы стали использовать в новом проекте?
Здравствуйте, koenjihyakkei, Вы писали:
K>В некоторых серьезных проектах видел как в классе переопределяют оператор new, для того чтобы выделять память через свой аллокатор.
K>Так вот вопрос, может я чего-то упустил, но я не могу найти плюсов у первого варианта по сравнению со вторым.
А где во втором варианте нестандартное выделение памяти?
В общем случае в первом варианте вместо malloc может быть что угодно -- например, при написании плагина к какой-нибудь системе "большие" куски памяти надо просить через подсистему хоста. Иначе в 32-битном режиме вылетим по Out Of Memory.
Во втором случае память выделяется стандартным new.
Или надо было уж расписывать malloc + placement new и возврат указателя, чтобы функционал двух вариантов совпадал, отличаясь синтаксисом.
Еще одно соображение: первый вариант позволяет одному экземпляру аллокатора работать с разными типами (разных размеров).
Во втором варианте экземпляр аллокатора будет на каждый класс, даже если у разных классов размеры совпадают.
Здравствуйте, K13, Вы писали:
K13>А где во втором варианте нестандартное выделение памяти? K13>В общем случае в первом варианте вместо malloc может быть что угодно -- например, при написании плагина к какой-нибудь системе "большие" куски памяти надо просить через подсистему хоста. Иначе в 32-битном режиме вылетим по Out Of Memory.
Да, там нестандартное выделение памяти, просто тут для упрощения написал malloc.
K13>Во втором случае память выделяется стандартным new. K13>Или надо было уж расписывать malloc + placement new и возврат указателя, чтобы функционал двух вариантов совпадал, отличаясь синтаксисом.
Да, наверное нужно было написать через malloc + placement new, но это тоже несущественно.
K13>Еще одно соображение: первый вариант позволяет одному экземпляру аллокатора работать с разными типами (разных размеров). K13>Во втором варианте экземпляр аллокатора будет на каждый класс, даже если у разных классов размеры совпадают.
Вот это уже существенное замечание. Действительно аллокатор используется для разных типов данных.
Но тогда второй вариант можно переписать так:
И тогда мы также можем использовать один аллокатор для аллоцирования разных типов.
Вообще мне кажется это все дело вкуса, но все равно даже с точки зрения вкуса почему первый вариант может быть лучше второго?
Почему собственно я спрашиваю, да просто нужно начинать новый проект, который базируется на готовом проекте, и я хочу ипользовать второй вариант использования аллокаторов, который мне кажется логичнее и проще.
Но прежде хотелось бы быть уверенным что я ничего не упустил и потом не придется все рефакторить.
K>template<class T> K>struct Allocator { K> template<typename Args...> K> T* Alloc(Args ... args) { K> return new T(std::forward<Args>(args)...); K> } K>};
K>Allocator<Foo> allocator; K>Foo* foo = allocator.Alloc(42); K>[/ccode] K>Так вот вопрос, может я чего-то упустил, но я не могу найти плюсов у первого варианта по сравнению со вторым. K>Вам какой больше нравится, что бы стали использовать в новом проекте?
1) Оба не нравятся, но первый лучше
2) Минусы первого -- не переопределён delete, что опасно. При таком подходе надо как-то следить что бы объекты разрушались на правильных аллокаторах. Например, хранить указатель на аллокатор в том же блоке, что и объект.
То есть, если не отвлекаться на выравнивание, то что-то вроде:
При этом, если do_alloc и do_free сделать виртуальными, то это всё можно будет хитро настраивать, а вызываться это всё будет обычным способом.
Мало того, если в Allocator добавить static или static per thread поле с текущим аллокатором и POII переключалку для него, то можно будет по умолчанию использовать обычный new, а аллокатор передавать через поле
Минусы второго подхода -- не гибкий, хотя и с шаблонами...
P. S.
В реальном коде ещё про new[] и delete[] стоит не забывать
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>1) Оба не нравятся, но первый лучше E>2) Минусы первого -- не переопределён delete, что опасно. При таком подходе надо как-то следить что бы объекты разрушались на правильных аллокаторах. Например, хранить указатель на аллокатор в том же блоке, что и объект. E>То есть, если не отвлекаться на выравнивание, то что-то вроде:
На самом деле delete переопределен, точнее он просто запрещен, потому что используются только арена аллокаторы.
E>Мало того, если в Allocator добавить static или static per thread поле с текущим аллокатором и POII переключалку для него, то можно будет по умолчанию использовать обычный new, а аллокатор передавать через поле
В свое время делал такое
Спасибо за наводку на thread_local, а то как-то мимо меня прошла эта фича.
E>Минусы второго подхода -- не гибкий, хотя и с шаблонами...
А мне он нравится свой простотой, которую даже сишники запросто поймут и не заметят. А то какой-то new с параметром...
..
Здравствуйте, koenjihyakkei, Вы писали:
K>А мне он нравится свой простотой, которую даже сишники запросто поймут и не заметят. А то какой-то new с параметром...
Зато явно всё.
Но всё равно на практике через thread_local удобнее обычно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском