Nuestro grupo especializado pasados algunos días de trabajo y de recopilar de información, obtuvimos los datos necesarios, esperamos que todo este artículo sea de gran utilidad en tu proyecto.
Los especificadores de clase de almacenamiento son parte del decl-specifier-seq de la sintaxis de declaración de un nombre. Junto con el alcance del nombre, controlan dos propiedades independientes del nombre: su duración de almacenamiento y es enlace.
|
(hasta C ++ 11) |
|
(hasta C ++ 17) |
static
– estático o hilo duración del almacenamiento y interno enlace.extern
– estático o hilo duración del almacenamiento y externo enlace.
|
(desde C ++ 11) |
mutable
– no afecta la duración del almacenamiento ni la vinculación. Consulte const / volatile para obtener una explicación.
Solo puede aparecer un especificador de clase de almacenamiento en una declaración excepto eso thread_local
puede combinarse con static
o con extern
(desde C ++ 11).
Explicación
1) los auto El especificador solo se permitió para objetos declarados en el alcance del bloque o en las listas de parámetros de función. Indicó la duración del almacenamiento automático, que es la predeterminada para este tipo de declaraciones. El significado de esta palabra clave se cambió en C ++ 11. |
(hasta C ++ 11) |
2) los register El especificador solo está permitido para objetos declarados en el alcance del bloque y en las listas de parámetros de función. Indica la duración del almacenamiento automático, que es la predeterminada para este tipo de declaraciones. Además, la presencia de esta palabra clave puede usarse como una sugerencia para que el optimizador almacene el valor de esta variable en un registro de CPU. Esta palabra clave quedó obsoleta en C ++ 11. |
(hasta C ++ 17) |
3) los static
El especificador solo se permite en las declaraciones de objetos (excepto en las listas de parámetros de funciones), declaraciones de funciones (excepto en el alcance del bloque) y declaraciones de uniones anónimas. Cuando se usa en una declaración de un miembro de clase, declara un miembro estático. Cuando se utiliza en una declaración de un objeto, especifica la duración del almacenamiento estático (excepto si va acompañado de thread_local
). Cuando se usa en una declaración en el ámbito del espacio de nombres, especifica el enlace interno.4) los extern
El especificador solo se permite en las declaraciones de variables y funciones (excepto miembros de clase o parámetros de función). Especifica el enlace externo y técnicamente no afecta la duración del almacenamiento, pero no se puede utilizar en una definición de un objeto de duración del almacenamiento automático, por lo que todos extern
los objetos tienen duraciones estáticas o de subprocesos. Además, una declaración de variable que usa extern
y no tiene inicializador no es una definición.
5) los thread_local La palabra clave solo se permite para objetos declarados en el ámbito del espacio de nombres, objetos declarados en el ámbito del bloque y miembros de datos estáticos. Indica que el objeto tiene una duración de almacenamiento de subprocesos. Puede combinarse con static o extern para especificar el enlace interno o externo (excepto para los miembros de datos estáticos que siempre tienen un enlace externo), respectivamente, pero que adicional static no afecta la duración del almacenamiento. |
(desde C ++ 11) |
Duración de almacenamiento
Todos los objetos de un programa tienen una de las siguientes duraciones de almacenamiento:
- automático duración del almacenamiento. El almacenamiento para el objeto se asigna al comienzo del bloque de código adjunto y se desasigna al final. Todos los objetos locales tienen esta duración de almacenamiento, excepto los declarados
static
,extern
othread_local
. - estático duración del almacenamiento. El almacenamiento para el objeto se asigna cuando comienza el programa y se desasigna cuando finaliza el programa. Solo existe una instancia del objeto. Todos los objetos declarados en el ámbito del espacio de nombres (incluido el espacio de nombres global) tienen esta duración de almacenamiento, más los declarados con
static
oextern
. Consulte Variables no locales y Variables locales estáticas para obtener detalles sobre la inicialización de objetos con esta duración de almacenamiento.
|
(desde C ++ 11) |
- dinámica duración del almacenamiento. El almacenamiento para el objeto se asigna y desasigna por solicitud mediante el uso de funciones de asignación de memoria dinámica. Consulte new-expression para obtener detalles sobre la inicialización de objetos con esta duración de almacenamiento.
Enlace
Un nombre que denota objeto, referencia, función, tipo, plantilla, espacio de nombres o valor, puede tener enlace. Si un nombre tiene vinculación, se refiere a la misma entidad que el mismo nombre introducido por una declaración en otro ámbito. Si una variable, función u otra entidad con el mismo nombre se declara en varios ámbitos, pero no tiene la vinculación suficiente, se generan varias instancias de la entidad.
Se reconocen los siguientes vínculos:
- sin vinculación. Solo se puede hacer referencia al nombre desde el ámbito en el que se encuentra.
- variables que no se declaran explícitamente
extern
(a pesar destatic
modificador); - clases locales y sus funciones miembro;
- otros nombres declarados en el ámbito del bloque, como typedefs, enumeraciones y enumeradores.
- enlace interno. Se puede hacer referencia al nombre desde todos los ámbitos de la unidad de traducción actual.
- variables, plantillas variables(desde C ++ 14), funciones o plantillas de funciones declaradas
static
; - No volátil sin plantilla(desde C ++ 14)no en línea(desde C ++ 17)variables calificadas const (incluido constexpr) que no están declaradas
extern
y no se ha declarado previamente que tengan vinculación externa; - datos de miembros de uniones anónimas.
Además, todos los nombres declarados en un espacio de nombres sin nombre o un espacio de nombres dentro de un espacio de nombres sin nombre, incluso los declarados explícitamente extern , tienen vinculación interna. |
(desde C ++ 11) |
- enlace externo. Se puede hacer referencia al nombre desde los ámbitos de las otras unidades de traducción. Las variables y funciones con enlace externo también tienen enlace de lenguaje, lo que hace posible vincular unidades de traducción escritas en diferentes lenguajes de programación.
- Cualquiera de los siguientes nombres declarados en el ámbito del espacio de nombres tiene un vínculo externo a menos que el espacio de nombres no tenga nombre o esté contenido dentro de un espacio de nombres sin nombre(desde C ++ 11):
- variables y funciones no enumeradas anteriormente (es decir, funciones no declaradas
static
, variables no constantes del ámbito del espacio de nombres no declaradasstatic
, y cualquier variable declaradaextern
); - enumeraciones;
- nombres de clases, sus funciones miembro, miembros de datos estáticos (const o no), enumeraciones y clases anidadas, y funciones introducidas por primera vez con declaraciones de amigos dentro de los cuerpos de las clases;
- nombres de todas las plantillas no enumeradas anteriormente (es decir, no las plantillas de funciones declaradas
static
).
- variables y funciones no enumeradas anteriormente (es decir, funciones no declaradas
- Cualquiera de los siguientes nombres declarados por primera vez en el alcance del bloque tiene un enlace externo:
- nombres de variables declaradas
extern
; - nombres de funciones.
- nombres de variables declaradas
Variables locales estáticas
Variables declaradas en el alcance del bloque con el especificador static
tienen una duración de almacenamiento estático pero se inicializan la primera vez que el control pasa por su declaración (a menos que su inicialización sea cero o constante, que se puede realizar antes de que se ingrese por primera vez al bloque). En todas las llamadas posteriores, se omite la declaración.
Si la inicialización arroja una excepción, la variable no se considera inicializada y la inicialización se intentará nuevamente la próxima vez que el control pase por la declaración.
Si la inicialización entra de forma recursiva en el bloque en el que se inicializa la variable, el comportamiento es indefinido.
Si varios subprocesos intentan inicializar la misma variable local estática al mismo tiempo, la inicialización se produce exactamente una vez (se puede obtener un comportamiento similar para funciones arbitrarias con Nota: las implementaciones habituales de esta función utilizan variantes del patrón de bloqueo doble verificado, que reduce la sobrecarga del tiempo de ejecución para las estáticas locales ya inicializadas a una única comparación booleana no atómica. |
(desde C ++ 11) |
El destructor de una variable estática de alcance de bloque se llama al salir del programa, pero solo si la inicialización se realizó correctamente.
Los objetos estáticos locales de función en todas las definiciones de la misma función en línea (que pueden estar implícitamente en línea) hacen referencia al mismo objeto definido en una unidad de traducción.
Notas
Nombres en el ámbito del espacio de nombres de nivel superior (ámbito de archivo en C) que son const
y no extern
tienen enlace externo en C, pero enlace interno en C ++.
Desde C ++ 11, auto
ya no es un especificador de clase de almacenamiento; se utiliza para indicar la deducción de tipo.
En C, la dirección de un |
(hasta C ++ 17) |
En C ++, a diferencia de C, las variables no se pueden declarar |
(desde C ++ 17) |
Nombres de thread_local
las variables con enlace interno o externo referidas desde diferentes ámbitos pueden referirse a la misma instancia oa diferentes instancias dependiendo de si el código se está ejecutando en el mismo hilo o en diferentes hilos.
los extern
La palabra clave también se puede usar para especificar el enlace de idioma y las declaraciones de instanciación de plantilla explícitas, pero no es un especificador de clase de almacenamiento en esos casos (excepto cuando una declaración está contenida directamente en una especificación de enlace de idioma, en la que caso de que la declaración sea tratada como si contuviera el extern
especificador).
La palabra clave mutable
es un especificador de clase de almacenamiento en la gramática del lenguaje C ++, aunque no afecta la duración del almacenamiento o la vinculación.
Especificadores de clase de almacenamiento, excepto para thread_local
, no están permitidos en especializaciones explícitas e instancias explícitas:
template<classT>structSthread_localstaticint tlm;;template<>thread_localint S<float>::tlm =0;// "static" does not appear here
Palabras clave
auto
, register
, static
, extern
, thread_local
, mutable
.
Ejemplo
#include#include #include #include thread_localunsignedint rage =1; std::mutex cout_mutex;voidincrease_rage(const std::string& thread_name)++rage;// modifying outside a lock is okay; this is a thread-local variable std::lock_guard<std::mutex>lock(cout_mutex); std::cout <<"Rage counter for "<< thread_name <<": "<< rage <<'n';intmain() std::thread a(increase_rage,"a"),b(increase_rage,"b"); std::lock_guard<std::mutex>lock(cout_mutex); std::cout <<"Rage counter for main: "<< rage <<'n'; a.join(); b.join();
Posible salida:
Rage counter for a:2 Rage counter for main:1 Rage counter for b:2
Informes de defectos
Los siguientes informes de defectos que cambian el comportamiento se aplicaron retroactivamente a los estándares C ++ publicados anteriormente.
DR | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 2387 | C ++ 14 | no está claro si la plantilla de variable calificada const tener enlace interno por defecto |
calificador const no afecta la vinculación de plantillas de variables o sus instancias |
Ver también
Aquí tienes las reseñas y valoraciones
Acuérdate de que tienes autorización de interpretar .