Повторное объявление вектора и вставки в циклических операциях - C ++

Обычно эта ошибка возникает, когда мы отправляем заголовок после эха или печати. Если эта ошибка возникает на определенной странице, убедитесь, что страница не выполняет эхо-сигналы перед вызовом start_session().

Пример непредсказуемой ошибки:

 <?php //a white-space before <?php also send for output and arise error
session_start();
session_regenerate_id();

//your page content

Еще один пример:

<?php
includes 'functions.php';
?> <!-- This new line will also arise error -->
<?php
session_start();
session_regenerate_id();

//your page content

Вывод: не выводить символ перед тем, как вызывать функции session_start() или header(), даже не с помощью пробела или новой строки

0
задан Akshay Kumar 16 January 2019 в 21:54
поделиться

1 ответ

1136 Я все еще подозреваю, что заданный вопрос - это не тот вопрос, который был задуман, но мне пришло в голову, что суть моего ответа, скорее всего, не изменится. Если вопрос обновляется, я всегда могу отредактировать этот ответ, чтобы он соответствовал (или удалял его, если он оказался неприменимым).

Отмена приоритетов оптимизации

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

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

Для задаваемого вопроса это означает, что основной проблемой должны быть не вычислительные затраты, а инкапсуляция. Почему вызывающему func() нужно выделять место для func() для работы? Это не должно происходить, если только профилировщик не определит это как узкое место в производительности. И если бы это сделал профилировщик, было бы намного проще (и надежнее!) Спросить профилировщика, помогает ли это изменение, чем запросить переполнение стека.

Почему?

Я могу придумать две основные причины для расстановки приоритетов оптимизации. Во-первых, «тест на нюх» ненадежен. Хотя может быть несколько человек, которые могут определить узкие места, глядя на код, многие, многие просто думают, что могут. Во-вторых, поэтому у нас есть оптимизирующие компиляторы. Это не неслыханно для кого-то, чтобы придумать этот сверхумный трюк оптимизации только, чтобы обнаружить, что компилятор уже делал это. Держите ваш код в чистоте, и пусть компилятор обрабатывает рутинные оптимизации. Только шаг, когда задача явно превышает возможности компилятора.

См. Также:

Выбор оптимизации

Хорошо, предположим, профилировщик идентифицировал конструкцию этого небольшого, 10- Элемент массива как узкое место. Следующий шаг - проверить альтернативу, верно? Почти. Во-первых, вам нужна альтернатива, и я считаю, что обзор теоретических преимуществ различных альтернатив будет полезен. Просто имейте в виду, что это теоретически, и что профайлер получает последнее слово. Поэтому я расскажу о плюсах и минусах альтернатив из этого вопроса, а также о некоторых других альтернативах, которые могут быть рассмотрены. Давайте начнем с худших вариантов, прокладывая себе путь к лучшим.

Пример A

В примере A вектор создается из 5 элементов, затем элементы помещаются в вектор до тех пор, пока i не встретится или не превысит размер вектора. Видя, как i и размер вектора увеличиваются на одну каждую итерацию (и i начинается меньше размера), этот цикл будет выполняться до тех пор, пока вектор не станет достаточно большим для сбоя программы. Это означает, вероятно, миллиарды итераций (несмотря на утверждение вопроса, что размер не будет превышать 10).

Легко самый дорогой в вычислительном отношении вариант. Не делай этого.

Пример B

В примере B вектор создается для каждой итерации внешнего цикла while, который затем доступен по ссылке из func(). Минусы производительности здесь включают передачу параметра в func() и наличие func() доступа к вектору косвенно через ссылку. Там нет плюсов производительности, поскольку это делает все, что будет делать базовый уровень (см. Ниже) , плюс некоторые дополнительные шаги.

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

Базовая линия

Базовая линия, которую я использую, является исправлением бесконечного цикла примера А. В частности, замените «my_vec.push_back(i);» примера В на «my_vec[i] = i;». Этот простой подход соответствует тому, что я ожидал от первоначальной оценки профилировщика. Если вы не можете победить простое, придерживайтесь этого.

Пример B *

В тексте вопроса представлена ​​неточная оценка примера B. Интересно, что оценка описывает подход, который потенциально может улучшить исходные данные. Чтобы получить код, который соответствует текстовому описанию, переместите «1111» примера B в строку непосредственно перед оператором while. Это приводит к созданию вектора только один раз, а не к каждой итерации.

Минусы этого подхода те же, что и в Примере B, который изначально был закодирован. Тем не менее, теперь мы получаем усиление в том, что конструктор вектора вызывается только один раз. Если строительство обходится дороже, чем затраты на косвенное обращение, результатом должно стать чистое улучшение, если цикл while повторяется достаточно часто. (Остерегайтесь этих условий: это значительное «если», и нет никакого априорного предположения о том, сколько итераций «достаточно».) Было бы разумно попробовать это и посмотреть, что говорит профилировщик.

Получить статический

Вариант в Примере B *, который помогает сохранить инкапсуляцию, заключается в использовании базовой линии (фиксированный Пример A), но перед объявлением вектора ключевым словом static. Это дает преимущество построения вектора только один раз, но без дополнительных затрат, связанных с созданием вектора в качестве параметра. Фактически, преимущество может быть больше, чем в примере B *, поскольку построение происходит только один раз за выполнение программы, а не каждый раз, когда запускается цикл while. Чем больше раз запускается цикл while, тем больше это преимущество.

Основным недостатком является то, что вектор будет занимать память во время выполнения программы. В отличие от примера B *, он не освободит свою память, когда закончится блок, содержащий цикл while. Использование этого подхода в слишком многих местах приведет к раздуванию памяти. Таким образом, хотя это целесообразно для профилирования этого подхода, вы можете рассмотреть другие варианты. (Конечно, если профилировщик называет это узким местом , затмевая все остальные, стоимость достаточно мала, чтобы заплатить.)

Исправьте размер

Мой личный выбор для какой оптимизации здесь попробовать начать с базовой линии и переключить вектор на std::array<10,double>. Моя основная мотивация заключается в том, что необходимый размер не будет больше 10. Также важно, что построение double тривиально. Построение массива должно быть на одном уровне с объявлением 10 переменных типа double, что, как я ожидаю, будет незначительным. Так что нет необходимости в хитроумных трюках по оптимизации. Просто дайте компилятору сделать свое дело.

Ожидаемое возможное преимущество этого подхода состоит в том, что vector выделяет пространство в куче для его хранения, что имеет накладные расходы. Местный array не будет иметь этой стоимости. Однако это только возможная выгода. Векторная реализация может уже использовать это соображение производительности для небольших векторов. (Возможно, он не использует кучу, пока емкость не должна превысить какое-то магическое число, возможно, больше 10.) Я бы сослался на вас раньше, когда упомянул «супер-умный» и «компилятор уже делал это». [1153 ] 1154 Я бы запустил это через профилировщик. Если нет никакой пользы, скорее всего, нет никакой пользы от других подходов. Дайте им попытку, конечно, поскольку они достаточно просты, но, вероятно, будет лучше использовать ваше время, чтобы взглянуть на другие аспекты для оптимизации.

0
ответ дан JaMiT 16 January 2019 в 21:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: