6 Basic concepts [basic]

6.7 Storage duration [basic.stc]

Этоstorage duration свойство объекта, которое определяет минимальное потенциальное время жизни хранилища, содержащего объект. Продолжительность хранения определяется конструкцией, используемой для создания объекта, и является одной из следующих:

  • статическая продолжительность хранения

  • продолжительность хранения потока

  • автоматическая продолжительность хранения

  • продолжительность динамического хранения

Длительности статического, потокового и автоматического хранения связаны с объектами, введенными с помощью объявлений ([basic.def]) иimplicitly created by the implementation. Продолжительность динамического хранения связана с объектами, созданными файлом new-expression.

Категории продолжительности хранения применимы и к ссылкам.

Когда достигается конец продолжительности области хранения, значения всех указателей, представляющих адрес любой части этой области хранения, становятсяinvalid pointer values. Косвенное обращение через недопустимое значение указателя и передача недопустимого значения указателя в функцию освобождения имеют неопределенное поведение. Любое другое использование недопустимого значения указателя имеет поведение, определяемое реализацией.37

Некоторые реализации могут определять, что копирование недопустимого значения указателя вызывает сгенерированную системой ошибку времени выполнения.

6.7.1 Static storage duration [basic.stc.static]

Все переменные, которые не имеют динамической продолжительности хранения, не имеют продолжительности хранения потоков и не являются локальными, имеютstatic storage duration. Хранение этих объектов должно длиться на время программы ([basic.start.static],[basic.start.term]).

Если переменная со статической продолжительностью хранения имеет инициализацию или деструктор с побочными эффектами, она не должна удаляться, даже если кажется, что она не используется, за исключением того, что объект класса или его копия / перемещение могут быть удалены, как указано в[class.copy].

Ключевое словоstatic можно использовать для объявления локальной переменной со статической продолжительностью хранения. [ Note:[stmt.dcl] описывает инициализацию локальныхstatic переменных;[basic.start.term] описывает уничтожение локальныхstatic переменных. ]end note

Ключевое слово,static примененное к члену данных класса в определении класса, дает статическую продолжительность хранения члена данных.

6.7.2 Thread storage duration [basic.stc.thread]

Все переменные, объявленные сthread_­local ключевым словом, имеютthread storage duration. Хранение этих объектов должно длиться в течение всего потока, в котором они созданы. Для каждого потока существует отдельный объект или ссылка, и использование объявленного имени относится к сущности, связанной с текущим потоком.

Переменная с продолжительностью хранения потока должна быть инициализирована до ее первойodr-use и, если она создана, должна быть уничтожена при выходе из потока.

6.7.3 Automatic storage duration [basic.stc.auto]

Блок-область видимости переменных явно не объявленыstatic,thread_­localилиextern есть automatic storage duration. Хранилище для этих сущностей длится до тех пор, пока блок, в котором они созданы, не завершится.

[ Note: Эти переменные инициализируются и уничтожаются, как описано в[stmt.dcl]. ]end note

Если переменная с автоматической продолжительностью хранения имеет инициализацию или деструктор с побочными эффектами, реализация не должна уничтожать ее до конца своего блока или исключать ее как оптимизацию, даже если она кажется неиспользуемой, за исключением того, что объект класса или его копирование / перемещение может быть удалено, как указано в[class.copy].

6.7.4 Dynamic storage duration [basic.stc.dynamic]

Объекты можно создавать динамически во времяprogram executionиспользования и уничтожать с помощью . Реализация C ++ обеспечивает доступ и управление динамической памятью через глобальное и глобальное и . [ Формы без выделения памяти, описанные в , не выполняют выделение или освобождение. ]new-expressionsdelete-expressionsallocation functionsoperator new operator new[] deallocation functionsoperator delete operator delete[]Note: [new.delete.placement]end note

Библиотека предоставляет определения по умолчанию для функций глобального распределения и освобождения. Некоторые функции глобального распределения и освобождения можно заменить ([new.delete]). Программа на C ++ должна предоставлять не более одного определения заменяемой функции выделения или освобождения. Любое такое определение функции заменяет версию по умолчанию, предоставленную в library ([replacement.functions]). Следующие функции выделения и освобождения ([support.dynamic]) неявно объявляются в глобальной области видимости в каждой единице трансляции программы.

void* operator new(std::size_t);
void* operator new(std::size_t, std::align_val_t);

void operator delete(void*) noexcept;
void operator delete(void*, std::size_t) noexcept;
void operator delete(void*, std::align_val_t) noexcept;
void operator delete(void*, std::size_t, std::align_val_t) noexcept;

void* operator new[](std::size_t);
void* operator new[](std::size_t, std::align_val_t);

void operator delete[](void*) noexcept;
void operator delete[](void*, std::size_t) noexcept;
void operator delete[](void*, std::align_val_t) noexcept;
void operator delete[](void*, std::size_t, std::align_val_t) noexcept;

Эти неявные декларации ввести только имена функций operatornew,operatornew[], operatordeleteиoperator delete[]. [ Note: Неявные декларации не вводить именаstd, std​::​size_­t, std​::​align_­val_­tили любые другие имена , которые библиотека использует , чтобы объявить эти имена. Таким образом, new-expression, delete-expressionили вызов функции , которая относится к одной из этих функций , не включая заголовок<new> правильно сформирован. Однако ссылка наstd orstd​::​size_­t илиstd​::​align_­val_­t неправильно сформирована, если имя не было объявлено путем включения соответствующего заголовка. ] Функции распределения и / или освобождения также могут быть объявлены и определены для любого класса ( ).end note[class.free]

Любые функции распределения и / или освобождения, определенные в программе C ++, включая версии по умолчанию в библиотеке, должны соответствовать семантике, указанной в[basic.stc.dynamic.allocation] и[basic.stc.dynamic.deallocation].

6.7.4.1 Allocation functions [basic.stc.dynamic.allocation]

Функция распределения должна быть функцией-членом класса или глобальной функцией; программа неправильно сформирована, если функция распределения объявлена ​​в области пространства имен, отличной от глобальной, или объявлена ​​статической в ​​глобальной области. Тип возврата должен бытьvoid*. Первый параметр должен иметь типstd​::​size_­t ([support.types]). Первый параметр не должен иметь ассоциированногоdefault argument. Значение первого параметра должно интерпретироваться как запрошенный размер выделения. Функция распределения может быть шаблоном функции. Такой шаблон должен объявлять свой возвращаемый тип и первый параметр, как указано выше (то есть типы параметров шаблона не должны использоваться в типе возвращаемого значения и первом типе параметра). Функции распределения шаблонов должны иметь два или более параметра.

Функция распределения пытается выделить запрошенный объем памяти. В случае успеха он должен вернуть адрес начала блока памяти, длина которого в байтах должна быть не меньше запрошенного размера. Нет ограничений на содержимое выделенной памяти при возврате из функции распределения. Порядок, непрерывность и начальное значение памяти, выделенной последовательными вызовами функции распределения, не определены. Возвращаемый указатель должен быть соответствующим образом выровнен, чтобы его можно было преобразовать в указатель на любой подходящий полный тип объекта ([new.delete.single]), а затем использовать для доступа к объекту или массиву в выделенной памяти (до тех пор, пока память не будет явно освобождена вызовом соответствующего функция освобождения). Даже если размер запрошенного пространства равен нулю, запрос может завершиться ошибкой. Если запрос завершается успешно, возвращаемое значение должно быть ненулевым значением указателя ([conv.ptr]), p0 отличным от любого ранее возвращенного значенияp1, если это значение неp1 было впоследствии передано в operatordelete. Кроме того, для функций распределения библиотек в[new.delete.single] и[new.delete.array], p0 должен представлять адрес блока памяти, отличного от хранилища для любого другого объекта, доступного для вызывающей стороны. Эффект косвенного обращения через указатель, возвращаемый как запрос нулевого размера, не определен.38

Функция распределения, которой не удается выделить хранилище, может вызвать установленную в данный момент функцию нового обработчика ([new.handler]), если таковая имеется. [ Поставляемая программой функция распределения может получить адрес установленного в данный момент с помощью функции ( ). ] Если функция распределения, имеющая не-бросание, не может выделить память, она должна вернуть нулевой указатель. Любая другая функция распределения, которой не удается выделить память, должна указывать на сбой только по типу, который соответствует типу of .Note: new_­handler std​::​get_­new_­handler [set.new.handler]end noteexception specificationthrowing an exception handler std​::​bad_­alloc

Функция глобального распределения вызывается только в результате anew expression, илиfunction call вызывается напрямую с использованием синтаксиса, или вызывается косвенно через вызовы функций в стандартной библиотеке C ++. [ Note: В частности, функция глобального распределения не вызывается для выделения памяти для объектов сstatic storage duration, для объектов или ссылок сthread storage duration, для объектов типаstd​::​type_­infoили для exception object. ]end note

Намерение состоит в том, чтобыoperator new() реализовать его с помощью вызоваstd​::​malloc() илиstd​::​calloc(), поэтому правила в основном те же. C ++ отличается от C тем, что требует нулевого запроса для возврата ненулевого указателя.

6.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]

Функции отмены распределения должны быть функциями-членами класса или глобальными функциями; программа плохо сформирована, если функции освобождения объявлены в области имен, отличной от глобальной, или объявлены статическими в глобальной области.

Каждая функция освобождения должна возвращать,void и ее первый параметр должен бытьvoid*. Функция освобождения может иметь более одного параметра. Ausual deallocation function - это функция освобождения, которая имеет:

  • ровно один параметр; или

  • ровно два параметра, тип второго - либо std​::​align_­val_­t или std​::​size_­t39; или

  • ровно три параметра: тип второго существаstd​::​size_­t и тип третьего существаstd​::​align_­val_­t.

Функция освобождения может быть экземпляром шаблона функции. Ни первый параметр, ни тип возвращаемого значения не должны зависеть от параметра шаблона. [ Note: То есть шаблон функции освобождения должен иметь первый параметр типаvoid* и тип возвращаемого значенияvoid (как указано выше). ] Шаблон функции освобождения должен иметь два или более функциональных параметра. Экземпляр шаблона никогда не является обычной функцией освобождения, независимо от его сигнатуры.end note

Если функция освобождения завершается выдачей исключения, поведение не определено. Значение первого аргумента, предоставленного функции освобождения, может быть значением нулевого указателя; если это так, и если функция освобождения предоставлена ​​в стандартной библиотеке, вызов не имеет никакого эффекта.

Если аргумент, переданный функции освобождения в стандартной библиотеке, является указателем, который не является указателем,null pointer valueфункция освобождения должна освободить память, на которую ссылается указатель, завершив продолжительность области хранения.

Глобальное значениеoperator delete(void*, std​::​size_­t) исключает использование функции распределенияvoid operator new(std​::​size_­t, std​::​size_­t) в качестве функции распределения размещения ([diff.cpp11.basic]).

6.7.4.3 Safely-derived pointers [basic.stc.dynamic.safety]

Аtraceable pointer object это

  • объектobject pointer type, или

  • объект интегрального типа размером не менееstd​::​intptr_­t, или

  • последовательность элементов в массиве narrow character type, где размер и выравнивание последовательности соответствуют таковым у некоторого типа указателя на объект.

Значение указателя являетсяsafely-derived pointer динамическим объектом, только если он имеет тип указателя на объект и является одним из следующих:

  • значение, возвращаемое вызовом реализации стандартной библиотеки C ++ ​::​operator new(std​::​​size_­t) или ​::​operator new(std​::​size_­t, std​::​align_­val_­t);40

  • результат взятия адреса объекта (или одного из его подобъектов), обозначенного lvalue в результате косвенного обращения через безопасно полученное значение указателя;

  • результат четко определенной арифметики указателя ([expr.add]) с использованием безопасно полученного значения указателя;

  • результат четко определенного преобразования указателя ([conv.ptr],[expr.cast]) безопасного значения указателя;

  • результатreinterpret_­cast безопасного получения значения указателя;

  • результатreinterpret_­cast целочисленного представления безопасного значения указателя;

  • значение объекта, значение которого было скопировано из отслеживаемого объекта-указателя, где во время копирования исходный объект содержал копию безопасно полученного значения указателя.

Целочисленное значение является значениемinteger representation of a safely-derived pointer только в том случае, если его тип не меньше размера,std​::​intptr_­t и это одно из следующих значений:

  • результатreinterpret_­cast безопасного получения значения указателя;

  • результат действительного преобразования целочисленного представления безопасного значения указателя;

  • значение объекта, значение которого было скопировано из отслеживаемого объекта-указателя, где во время копирования исходный объект содержал целочисленное представление безопасно полученного значения указателя;

  • результат аддитивной или побитовой операции, один из операндов которой является целочисленным представлением безопасно полученного значения указателяP, если этот результат, преобразованный с помощью,reinterpret_­cast<void*> будет сравниваться с безопасным полученным указателем, вычисляемым изreinterpret_­cast<void*>(P).

Реализация может иметьrelaxed pointer safety, и в этом случае действительность значения указателя не зависит от того, является ли это безопасным значением указателя. В качестве альтернативы, реализация может иметьstrict pointer safety, и в этом случае значение указателя, относящееся к объекту с длительностью динамического хранения, которое не является безопасным значением указателя, является недопустимым значением указателя, если указанный полный объект не был ранее объявлен достижимым ([util.dynamic.safety]). [ Note: Эффект от использования недопустимого значения указателя (включая передачу его в функцию освобождения) не определен, см[basic.stc.dynamic.deallocation]. Это верно, даже если значение указателя, полученное небезопасно, может сравниться с некоторым значением указателя, полученным безопасным способом. ] Это определяется реализацией, имеет ли реализация ослабленную или строгую безопасность указателя.end note

Этот раздел не налагает ограничений на косвенное обращение через указатели к памяти, не выделенной​::​operator new. Это поддерживает способность многих реализаций C ++ использовать двоичные библиотеки и компоненты, написанные на других языках. В частности, это относится к двоичным файлам C, потому что косвенное обращение через указатели к памяти, выделенной имstd​::​malloc , не ограничено.

6.7.5 Duration of subobjects [basic.stc.inherit]

Продолжительность хранения подобъектов и ссылочных элементов - это время хранения их полного объекта ([intro.object]).