Я и не утверждал, что это в стандарте написано. Я хочу сказать, что дебаг режим не обязан поддерживать стандарт в требованиях эффективности. Главное, чтобы семантику не портил. Ведь польза этого режима как раз во всевозможных «тормозных» проверках. Иначе этот режим потеряет смысл, следуя требованиям эффективности
1. Самой логичной реализацией итераторов для std::vector является обычный указатель (завернутый в обертку или даже без нее). Отсюда такое поведение в релизе.
2. В отладочном режиме MS VC2008 и выше (скорее всего и в других компиляторах также) Вы получите кучу debug-assert'ов на своем примере. В debug как раз есть проверки на принадлежность итераторов конкретному контейнеру и многие другие проверки. Но в release такие проверки — это лишний оверхед.
3. Смысл сложения 2-х итераторов? Что в результате? Вычитание же не обделено смыслом.
Насчет оптимизации передачи аргумента const X&:
Если функция встраивается (inline), то никакого получения адреса / разыменования внутри функции не будет. Если встраивается ее вызов, тогда да, будет.
Для написания переносимого кода можно воспользоваться boost::param_type<X>::type. Буст поможет решить, как передавать параметр: по константной ссылке или по значению.
Порядок, да, может быть любым. Но, если рассматривать одну конкретную переменную, то dimoclus прав: сразу после выполнения mov [mem],value в [mem] увидим значение value с любого ядра. Это гарантирует когерентность кэша. Протоколы разные, но почти все архитектуры их имеют (за исключением парочки экзотических). Перед тем как прочитать [mem] гарантируется, что протокол поддержки когерентности отработал.
Вот хорошая ссылка по Memory Barriers.
Ваши функции, к сожалению, не могут возвращать значения. Вернее они возвращают значение типа класса, который они конструируют. В BOOST_LOCAL_FUNCTION уже есть решение вложенных функций.
Попробуйте оба варианта в релизе с максимальной настройкой оптимизации компилятора, сделайте замеры производительности на хорошо нагруженном примере и сравните. Если [=] окажется не менее производительным, чем [&], выбрасывайте список, код упростится.
А статический список, если я правильно понял, используется только для вечного хранения realfunc объектов, он всегда растет при конструировании func_t и очищается только по завершении программы? Я бы посмотрел в сторону shared_ptr и хранил бы его вместо realfunc *f, если нет циклических ссылок. Список был бы не нужен.
Все верно. Я вот тут посидел, повспоминал, вроде никогда не использовал list. В основном vector. В случае больших массивов, в которые в конец идут частые вставки — deque. Полагаю, что list следует использовать в специфических задачах не для получения производительности, а когда по каким-то причинам нам очень не хочется, чтобы элементы перемещались в памяти и не портились указатели и итераторы на них. Скорее всего, он будет полезен для построения графов, где часто добавляются и удаляются вершины с ребрами, которые ссылаются друг на друга через указатели. По-моему, в Boost Graph Library в самая популярное представление графа строится на std::list (класс adjacency_list).
Дык то ж семантика, а не предлагаемая реализация. То есть, описывается эквивалент, который будет давать тот же семантический результат, что и size(). То есть, стандарт требует, чтобы distance(a.begin(),
a.end()) == a.size().
Мне нравится как перегрузка с наследованием решена в C++. В перегрузке участвуют только методы того типа, у которого мы их вызываем, имена методов базового класса скрываются (hide) независимо от виртуальности. Если разработчик хочет, чтобы имя в производном классе было перегружено совместно с именем из базового класса, он это указывает явно, внесением имени в область видимости производного класса: using base::foo; (unhide). Вот и все, четко и понятно, никаких неожиданностей. Тема перегрузки и тема замещения виртуальной функции в C++ не пересекаются. Могли бы для шарпа что-то подобное придумать.
Пример:
struct base
{
void foo(int);
};
struct derived : base
{
// using base::foo; // раскомментить для перегрузки с foo(int)
void foo(double);
};
В данном примере LoadLibrary(«ntdll.dll») не вызовет течь. Под NT ntdll.dll и так всегда загружена в процесс. Лишь инкрементирует счетчик загруженной библиотеки. Разве что не эстетично это. Так лучше было бы: GetModuleHandle(«ntdll.dll»).
2. В отладочном режиме MS VC2008 и выше (скорее всего и в других компиляторах также) Вы получите кучу debug-assert'ов на своем примере. В debug как раз есть проверки на принадлежность итераторов конкретному контейнеру и многие другие проверки. Но в release такие проверки — это лишний оверхед.
3. Смысл сложения 2-х итераторов? Что в результате? Вычитание же не обделено смыслом.
Если функция встраивается (inline), то никакого получения адреса / разыменования внутри функции не будет. Если встраивается ее вызов, тогда да, будет.
Для написания переносимого кода можно воспользоваться
boost::param_type<X>::type
. Буст поможет решить, как передавать параметр: по константной ссылке или по значению.Вот хорошая ссылка по Memory Barriers.
Может, я чего-то не учел.
Хотя, коряво все это выглядит без лямбд.
a.end()) == a.size().
Пример: