Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 [ 8 ] 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

Окончание табл. 3.1

sprintf

snprintf

stringstream

strstrearr

boost: :!exical cast

Время работы no отношению к .sprintf

Borland С++ 5.5.1 / Wi!idow,s

12,6

19,7

Gnu g++ 2.95.2 / Cygwin + Windows

Microsoft VC7 / Windows

13,2

19,2

Rogue Wave 2.1,1 / SunPro 5.3 / SunOS 5.7

16,5

Rogue Wave 2,2.1 / HP aCC 3.30/ HP-UX 11,00

Таблица 3.2. Правила применения методов форматирования строк

По умолчанию, когда эффективность не так

важна

Там, где эффективность важна, и профилирование подтверждает необходимость оптимизации

Простое конвертирование в строковое представление

Простое форматирование .!Иоо работа с широкими строка.ми или в шаблонах

Сложное форматирование при отсутствии необходимости в работе с широкими строками или в шаблонах

boost: : 1 exi cal „cast

std:;stri ngstream или std::strstream

snprintf

std::strstream или snprintf

std::strstream или snprintf

snpri ntf

В заключение отмстим несколько интересных возможностей, предусмотренных в strstream. Не последняя из них -- возможность выбора .между использованием встроенного или предоставляемого программистом буфера. Его существенный технический недостаток состоит в определенной "хрупкости", связанной с необходимостью использования завершения строки при помощи ends. Важный (назовем его "социальным") недостаток заключается в том, что следует учитьшать (пусть и небольшую) вероятность того, что в один прекрасный день и комитет по стандарту С+ + , и производитель вашего компилятора решат избавиться от strstream. Честно говоря, очень странно видеть такую хорошую вещь нежелательной. Как видим, даже в стандарте некоторые животные равнее других,,.

Проводилось усреднение по трем запускам каждой программы, в которых выполнялось по 1 млн, вызовов кода соо~ветствующих примеров. Результаты мог>т зависеть от используемых версии компиляторов и опций компиляции



Задача 4. Функции-члены стандартной

библиотеки Сложность: 5

Повторное использование - это хорошо, но всегда ли допустимо использование возможностей стандартной библиотеки с ней самой? Вот небольшой пример, который может вас удивить. В нем рассматривается возможность стандартной библиотеки, которая может быть переносимо использована с любым вашим кодом, но только не с самой стандартной библиотекой.

Вопрос для новичка

1. Что такое std: :mem fun? Когда можно использовать std: : mem„f un? Приведите пример.

Вопрос для профессионала

2. Полагая, что в комментарии в приведенном коде все правильно, ответьте на вопрос: является ли приведенный код корректным и переносимым кодом С-+? Обоснуйте свой ответ.

std::mem fun</*...*/>( &std::vector<int>::clear )

Решение

Игры с mem fun

1. Что такое std: : mem...fun? Когда можно использовать std: :mem f un? Приведите

пример.

Стандартньп-i адаптер mem„fun позволяет нам использовать функции-члены в алгорит-,мах ставдартиой библиотеки и другом коде, который обычно работает с функииями, не являющимися членами класса (свободными функциями). Пусть, например, мь! имеем

class Employee { publi с:

int DoStandardRai se() { /...-/ }

int Gi veStandardRai se( Employee& e ) { return e.DoStandardRaiseC);

std::vector<Employee> emps;

Мы >же привыкли писать, например, следующим образом.

std::for„each( emps.beginC), emps.end(), &GiveStandardRaise );

Ho что, если функции Gi veStandardRai se() не существует или по каким-то иным причинам нам надо вызвать функцию-член не;10срсдствснно? Тогда мы можем написать следующий код.

std:;vector<Emplоуее> emps;

std::for„each(emps.begi nC), emps.end(),

std : : rr.em f un„ref (&Empl oyee : : DoStandardRai se)) ;

Суффикс „ref в конце mem fun ref - дань историческим тр;а.дициям. Когда мы пишем код наподобие приведенного, мы просто должны помнить, что надо использовать mem fun ref, если имеем дело с обычным контейнером с объектами и for eath работает со ссылками на эти объекты, и использовать nem„.fun. cl.ih контейнер содержит указатели на объекты.



std::vector<Employee*> emp ptrs;

std::for each(emp ptrs.begin(), emp ptrs.end(),

std::mem „fun(&Employee::DoStandardRai se));

Вы, вероятно, обратили внимание, что для ясности я воспользовался функцией без параметров. Вы можете воспользоваться вспомогательными классами bind... для функций с аргументом - принцип при этом остается тот же. К сожалению, вы не можете использовать этот подход для функций с двумя и более параметрами.

Вот, по сути, главное, что надо знать о mem „fun. И это подводит нас к трудной части задачи.

Используйте mem fun, но не со стандартной библиотекой

2. Полагая, что в комментарии в приведенном коде все правильно, ответьте на вопрос: является ли приведенный код корректным и переносимым кодом С++? Обоснуйте свой ответ.

std::mem fun</*...*/>( &std::vector<int>::cl ear )

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

std: :mem fun<void, std: :vector<int, std: :anocator<int> > > ( &std::vector<int>::clear);

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

Вы можете удивиться моим примечанием "в зависимости от вашей реализации стандартной библиотеки". В конце концов, сигнатура std: : vector<i ni>: : clear гласит, что эта функция не получает параметров и ничего не возвращает, ведь так? Разве стандарт не говорит нам об этом?

По сути, в этом и заключается главный вопрос задачи.

Спецификация стандартной библиотеки сознатель[то предоставляет разработчикам определенную свободу действий по реализации функций-членов. В частности:

• еи1 натура функции-члена с параметрами по умолчанию может бьпъ заменена "двумя или более сигнатурами функций-членов с эквивалентным поведением";

• сигнатура функции-члена может иметь дополнительные параметры по умолчанию.

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

В большинстве случаев в этом нет никаких проблем, и все эти параметры по умолчанию просто остаются незамеченными. Например, при вызове функции-члена эти скрытые параметры, которых вы не передаете, попадают в функцию в виде значений по умолчанию, и вы даже не подозреваете об их существовании. Но, к сожалению, эти параметры начинают играть важную роль, когда ста1ювится важна точная сигнатура функции - например, когда вы пытаетесь использовать mem„fun, За.метим, что это происходит, даже если ваш компилятор корректно выводит аргументы шаблонов. Это связано с двумя потенциальными проблема.ми.

• Если рассматриваемая функция-член полчает параметр, о котором вы не подозревали, вам понадобится написать что-то наподобие std:; bi nd2nd для того, чтобы избавиться от него (более подробное описание использования стандартных замыканий параметров функции можно найти в [Josuttis99j)- Конечно, после этого ваш код ие будет работать в реализации, где используется дополнительный



0 1 2 3 4 5 6 7 [ 8 ] 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85