Как работает передача объектов по значению в 1С и почему объект не копируется?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С программисты часто сталкиваются с ситуацией, когда использование ключевого слова Знач при передаче параметра в функцию ведет себя не так, как ожидается. Особенно это касается сложных (агрегатных) типов данных, таких как ДокументОбъект, СправочникОбъект, Массив или Структура. Разберем детально, почему при передаче объекта "по значению" изменения внутри функции отражаются на исходном объекте, и как на самом деле устроена работа с памятью в системе.

Природа агрегатных типов и указателей в памяти

Для начала проанализируем, что именно хранится в переменной, когда мы присваиваем ей сложный объект. В 1С, как и во многих современных языках программирования, переменные для простых типов (например, Число, Булево, Дата) хранят непосредственно само значение. Однако для агрегатных типов переменная хранит не весь набор данных объекта, а указатель (ссылку на область памяти), где этот объект физически расположен.

Рассмотрим ситуацию на примере кода:


&НаСервереБезКонтекста
Процедура ПроверкаСтруктурыНаСервере()
    Док = Документы.Заявка.СоздатьДокумент();
    Док1 = ОбъектПоЗначению(Док);
    
    // Сравнение покажет Истину, так как обе переменные 
    // указывают на один и тот же адрес в памяти
    Б = (Док = Док1); 
КонецПроцедуры

&НаСервереБезКонтекста
Функция ОбъектПоЗначению(Знач ВходящийДок)
    Возврат ВходящийДок;
КонецФункции

Когда мы вызываем функцию и передаем туда Док с ключевым словом Знач, система действительно копирует значение. Но что является значением в данном случае? Значением является адрес в памяти. В итоге внутри функции переменная ВходящийДок содержит тот же самый адрес, что и исходная переменная Док. Любое изменение реквизита через ВходящийДок — это изменение данных по тому же адресу, к которому обращается и основная процедура.

Различие между ссылкой и объектом

Важно не путать типы данных ДокументСсылка и ДокументОбъект. Проанализируем их поведение:

  1. ДокументСсылка: Это неизменяемый идентификатор (GUID). Если вы передадите ссылку в функцию, вы не сможете изменить данные самого документа в базе через эту переменную, не получив объект. Ссылка всегда передается по значению своего идентификатора.
  2. ДокументОбъект (или СправочникОбъект): Это структура в оперативной памяти, предназначенная для редактирования. Именно здесь проявляется эффект "общего адреса". Даже если объект еще не записан в базу данных (как в примере с СоздатьДокумент()), он уже занимает место в RAM, и переменные лишь "ссылаются" на него.

Передача параметров между Клиентом и Сервером

Выясним причину, по которой поведение системы меняется при вызове серверного метода с клиента. Это один из самых важных нюансов платформы 1С.

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

Рассмотрим, как это работает:

Таким образом, внутри одного контекста (например, Сервер -> Сервер) Знач для объектов копирует только указатель. А при переходе границы Клиент -> Сервер Знач фактически создает независимую копию на время выполнения вызова.

Как создать реальную (глубокую) копию объекта?

Если перед нами стоит задача передать объект в функцию так, чтобы гарантированно не изменить исходные данные, обычного Знач недостаточно. Нам нужно "клонировать" объект. В 1С нет универсального метода Клонировать() для всех типов, поэтому рассмотрим пошагово, как это сделать для разных случаев:

Способ 1: Использование метода Скопировать()

Для объектных типов метаданных (Документы, Справочники) существует встроенный метод. Проанализируем пример:


НовыйОбъект = ИсходныйОбъект.Скопировать();
// Теперь НовыйОбъект и ИсходныйОбъект — это разные сущности в памяти.
// Изменение одного не влияет на другой.

Способ 2: Сериализация (Универсальный метод)

Для таких типов, как Структура, Массив или ТаблицаЗначений, можно использовать преобразование в XML или JSON и обратно. Это гарантирует создание абсолютно нового экземпляра данных.


// Пример через ЗначениеВСтрокуВнутр (для простых структур)
СтрокаДанных = ЗначениеВСтрокуВнутр(ИсходнаяСтруктура);
КопияСтруктуры = ЗначениеИзСтрокиВнутр(СтрокаДанных);

Сравнение объектов оператором "Равно"

Вернемся к примеру автора: Б = (Док = Док1). Посмотрим на ситуацию внимательнее. В 1С оператор сравнения для объектных типов проверяет идентичность. Это означает, что система спрашивает: "Указывают ли эти две переменные на один и тот же адрес в памяти?".

Если вы создадите два разных документа программно с абсолютно идентичными реквизитами:


Док1 = Документы.Заявка.СоздатьДокумент();
Док2 = Документы.Заявка.СоздатьДокумент();
// Заполним их одинаково...
Б = (Док1 = Док2); // Вернет ЛОЖЬ

Несмотря на то, что данные внутри одинаковы, это два разных объекта в памяти. В примере же из обсуждения, Док1 получил значение указателя от Док через функцию, поэтому результат сравнения — Истина.

Итоги и рекомендации

Подводя итог, при работе с агрегатными типами в 1С следует помнить:

  1. Ключевое слово Знач для объектов не создает копию данных внутри одного контекста выполнения. Оно лишь защищает саму переменную от перезакрепления за другим объектом, но не защищает свойства объекта от изменения.
  2. Если вам нужна изоляция данных — используйте метод Скопировать() или механизмы сериализации.
  3. Всегда учитывайте контекст: передача данных между клиентом и сервером всегда подразумевает копирование данных из-за особенностей сетевого взаимодействия. Для обеспечения стабильной работы системы при внедрении подобных механизмов можно использовать автоматическое архивирование и тестирование баз 1С.
  4. Для проверки, являются ли две переменные одним и тем же объектом, используйте простое сравнение =.

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

← На главную