В процессе разработки на платформе 1С:Предприятие 7.7 часто возникает задача обрезать «хвост» таблицы значений (ТЗ). Например, после выполнения запроса или сортировки нам требуется оставить только первые N строк. Самым очевидным и быстрым способом кажется прямое переопределение количества строк. Однако в среде разработчиков «семерки» долгое время ходили слухи о небезопасности такого метода. Разберем детально, как работает этот механизм, в чем заключаются реальные риски и как их избежать.
Рассмотрим стандартную ситуацию. У нас есть объект ТаблицаЗначений, в котором содержится 100 строк. Нам необходимо оставить только первые 95. Мы можем использовать следующий код:
// Пример обрезания ТЗ
ТЗ.КоличествоСтрок(95);
Проанализируем, что происходит «под капотом» платформы. Метод КоличествоСтрок при передаче в него параметра, меньшего текущего значения, просто изменяет внутренний указатель (счетчик) количества доступных строк в объекте. С точки зрения стандартной платформы 1С 7.7, это законная и документированная операция. Все строки, индекс которых превышает новое значение, становятся недоступными для методов перебора, поиска и обращения по индексу.
Посмотрим на альтернативный вариант — удаление строк в цикле с конца таблицы. Это могло бы выглядеть так:
// Удаление строк в цикле
Для Ном = 1 По 5 Цикл
ТЗ.УдалитьСтроку(ТЗ.КоличествоСтрок());
КонецЦикла;
Выясним причину, почему первый вариант предпочтительнее. Использование КоличествоСтрок(N) работает за константное время O(1). Платформа просто меняет одно числовое значение в заголовке структуры ТЗ. Метод УдалитьСтроку, даже если он удаляет последнюю строку, требует большего количества ресурсов на обслуживание связей внутри объекта. Если же удаление происходит из середины, системе приходится физически сдвигать вышестоящие элементы в памяти, что на больших таблицах (десятки тысяч строк) приводит к катастрофическому падению производительности.
Многие разработчики опасаются использовать КоличествоСтрок(N) для уменьшения таблицы, ссылаясь на возможные ошибки при последующей сортировке или поиске. Проанализируем, откуда взялись эти опасения. Как показывают обсуждения на профильных форумах, основные проблемы возникали не в штатной конфигурации, а при использовании внешней компоненты 1CPP.dll.
В расширении 1CPP существует объект ИндексированнаяТаблица. Вот в нем прямое изменение количества строк через КоличествоСтрок() действительно могло привести к критическим ошибкам (Access Violation). Это происходило из-за того, что индексы, построенные компонентой для быстрого поиска, не обновлялись автоматически при «силовом» изменении счетчика строк 1С. В результате компонента пыталась обратиться к данным по старым индексам, которые указывали на уже «отсеченную» область памяти.
Важно: Если вы используете стандартную ТаблицаЗначений без внешних надстроек, метод КоличествоСтрок(N) абсолютно безопасен.
Рассмотрим ситуацию с точки зрения потребления оперативной памяти. Когда мы обрезаем таблицу, физическая память, выделенная под удаленные строки, не всегда освобождается немедленно. 1С 7.7 склонна удерживать зарезервированный объем памяти до тех пор, пока объект ТЗ не будет полностью уничтожен или переинициализирован методом Очистить().
Также проанализируем поведение агрегатных объектов. Если в колонках таблицы хранились ссылки на другие объекты (например, другие ТЗ или СпискиЗначений), то при выполнении ТЗ.КоличествоСтрок(95) ссылки на объекты в строках с 96 по 100 будут разорваны. Однако деструкторы этих объектов сработают в соответствии с внутренними алгоритмами 1С, что в редких случаях может вызвать временное удержание памяти.
Разберем типичную ошибку, которую часто принимают за «баг» платформы. Никогда не изменяйте количество строк таблицы внутри цикла, который обходит эту же таблицу по индексам. Посмотрим на ошибочный пример:
// ОШИБОЧНЫЙ КОД
Для Ном = 1 По ТЗ.КоличествоСтрок() Цикл
Если ТЗ.ПолучитьЗначение(Ном, "Статус") = "Удалить" Тогда
// Попытка обрезать таблицу прямо во время итерации
ТЗ.КоличествоСтрок(ТЗ.КоличествоСтрок() - 1);
КонецЕсли;
КонецЦикла;
В данном случае счетчик цикла Ном может выйти за пределы фактически установленного количества строк, что приведет к ошибке выполнения. Для корректной очистки или обрезания таблицы всегда рассчитывайте новое количество строк заранее или производите операцию после завершения цикла обхода.
Подведем итог нашему анализу:
ТаблицаЗначений в 1С 7.7 метод КоличествоСтрок(N) является штатным, быстрым и безопасным способом удаления строк с конца.1CPP и объект ИндексированнаяТаблица. В этом случае используйте специализированные методы компоненты для удаления строк.Сортировать() в штатной ТЗ корректно учитывает новое количество строк после обрезания «хвоста».Таким образом, мы можем уверенно использовать КоличествоСтрок(N) для оптимизации работы с данными, не опасаясь за стабильность системы в рамках стандартного функционала платформы.