Я предлагаю подход на основе итератора/обратного вызова в тех случаях, когда вы требуете наиболее легкого решения.
Причина заключается в том, что разъединяет поставщика от характера использования в потребителем.
В частности, хлопнув результат в коллекцию (даже если результат может быть «оптимизированной» - скорее всего, в (N) РВО или перемещение вместо копирования объекта) будет по-прежнему выделять полный контейнер для полной мощности ,
Edit: отличное дополнение к «обязательные документы» (они не, они просто невероятно полезно, если вы хотите, чтобы понять вещи): Want Speed? Pass By value Дейва Абрахамс.
Теперь
это перебор, если потребитель фактически прекращает обработку данных после первых нескольких элементов
for(auto f=myType.begin(), l=myType.end(); f!=l; ++f)
{
if (!doProcessing(*f))
break;
}
это может быть неоптимальным даже если потребитель обрабатывает все элементы в конечном итоге: там может не быть b e необходимо, чтобы все элементы были скопированы в какой-либо конкретный момент, поэтому «слот» для «текущего элемента» можно повторно использовать, уменьшая требования к памяти, увеличивая местность кеша. Например.:
for(auto f=myType.begin(), l=myType.end(); f!=l; ++f)
{
myElementType const& slot = *f; // making the temp explicit
doProcessing(slot);
}
Обратите внимания, что итераторы интерфейсы просто еще выше, если потребителясделал хочет коллекцию, содержащую все элементы:
std::vector<myElementType> v(myType.begin(), myType.end());
// look: the client gets to _decide_ what container he wants!
std::set<myElementType, myComparer> s(myType.begin(), myType.end());
попытаться получить эту гибкость иначе.
Наконец, есть некоторые элементы стиля:
по своей природе это легко разоблачить (константные) ссылки на элементы с помощью итераторов; это значительно облегчает устранение объекта нарезки и позволяет клиентам использовать элементы полиморфно.
интерфейсы в стиле итератора могут быть перегружены, чтобы возвращать неконстантные ссылки на разыменование. Контейнер должен быть возвращен, не может содержать ссылки (непосредственно)
, если вы будете придерживаться требований диапазона, ориентированного на в C++ 11 вы можете иметь некоторые синтаксический сахар:
for (auto& slot : myType)
{
doProcessing(slot);
}
Наконец, (как показано выше), в общем смысле итераторы прекрасно работают со стандартной библиотекой.
Стиль обратного вызова (а так же стиль Output-итератор) имеет много преимуществ стиля итератора (а именно, вы можете использовать возвращаемые значения для прерывания итерации на полпути, и вы могли бы сделать обработку без выделения копии всех элементов спереди), но мне кажется, что он немного менее гибкий в использовании. Конечно, могут быть ситуации, когда вы хотите поощрять конкретную модель использования, и это смешение должно быть хорошим способом.
Yikes, комментарии к этому вопросу исчезли! Был один комментарий с ссылкой на «обязательный документ». Может ли кто-нибудь отправить ссылку еще раз? Благодаря! –
@ChristianAmmer I _think_ это был [этот] (http://c2.com/cgi/wiki?PrematureOptimization). Тем не менее, есть несколько «семенных частей» вокруг одного и того же предмета, плавающего вокруг межотраслевых элементов. – sehe