Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Uma classe de armazenamento no contexto de declarações de variáveis C++ é um especificador de tipo que governa o tempo de vida, a ligação e o local da memória de objetos. Um determinado objeto pode ter apenas uma classe de armazenamento. As variáveis definidas dentro de um bloco têm armazenamento automático, a menos que especificado de outra forma usando o extern, staticou thread_local especificadores. Objetos e variáveis automáticas não têm ligação; eles não são visíveis para codificar fora do bloco. A memória é alocada para eles automaticamente quando a execução entra no bloco e é desalocada quando o bloco é encerrado.
Observações
A
mutablepalavra-chave pode ser considerada um especificador de classe de armazenamento. No entanto, ele só está disponível na lista de membros de uma definição de classe.Visual Studio 2010 e posterior: A
autopalavra-chave não é mais um especificador de classe de armazenamento C++ e aregisterpalavra-chave foi preterida. Visual Studio 2017 versão 15.7 e posterior: (disponível no/std:c++17modo e posterior): Aregisterpalavra-chave é removida da linguagem C++. Seu uso causa uma mensagem de diagnóstico:// c5033.cpp // compile by using: cl /c /std:c++17 c5033.cpp register int value; // warning C5033: 'register' is no longer a supported storage class
static
A static palavra-chave pode ser usada para declarar variáveis e funções no escopo global, escopo do namespace e escopo da classe. As variáveis estáticas também podem ser declaradas no âmbito local.
Duração estática significa que o objeto ou variável é alocado quando o programa é iniciado e é desalocado quando o programa termina. Ligação externa significa que o nome da variável é visível de fora do arquivo onde a variável é declarada. Por outro lado, a ligação interna significa que o nome não é visível fora do arquivo onde a variável é declarada. Por padrão, um objeto ou variável definido no namespace global tem duração estática e ligação externa. A static palavra-chave pode ser usada nas seguintes situações.
Quando você declara uma variável ou função no escopo do arquivo (escopo global e/ou namespace), a
staticpalavra-chave especifica que a variável ou função tem ligação interna. Quando você declara uma variável, a variável tem duração estática e o compilador a inicializa como 0, a menos que você especifique outro valor.Quando você declara uma variável em uma função, a
staticpalavra-chave especifica que a variável mantém seu estado entre chamadas para essa função.Quando você declara um membro de dados em uma declaração de classe, a
staticpalavra-chave especifica que uma cópia do membro é compartilhada por todas as instâncias da classe. Umstaticmembro de dados deve ser definido no escopo do arquivo. Um membro de dados integral que você declara comoconst staticpode ter um inicializador.Quando você declara uma função de membro em uma declaração de classe, a
staticpalavra-chave especifica que a função é compartilhada por todas as instâncias da classe. Umastaticfunção de membro não pode acessar um membro da instância porque a função não tem um ponteiro implícitothis. Para acessar um membro da instância, declare a função com um parâmetro que seja um ponteiro ou referência da instância.Não é possível declarar os membros de um
unioncomostatic. No entanto, um globalmente declarado anónimouniondeve ser explicitamente declaradostatic.
Este exemplo mostra como uma variável declarada static em uma função mantém seu estado entre chamadas para essa função.
// static1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void showstat( int curr ) {
static int nStatic; // Value of nStatic is retained
// between each function call
nStatic += curr;
cout << "nStatic is " << nStatic << endl;
}
int main() {
for ( int i = 0; i < 5; i++ )
showstat( i );
}
nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10
Este exemplo mostra o uso de static em uma classe.
// static2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class CMyClass {
public:
static int m_i;
};
int CMyClass::m_i = 0;
CMyClass myObject1;
CMyClass myObject2;
int main() {
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
myObject1.m_i = 1;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
myObject2.m_i = 2;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
CMyClass::m_i = 3;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
}
0
0
1
1
2
2
3
3
O exemplo a seguir mostra uma variável local declarada static em uma função membro. A static variável está disponível para todo o programa, todas as instâncias do tipo compartilham a mesma cópia da static variável.
// static3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct C {
void Test(int value) {
static int var = 0;
if (var == value)
cout << "var == value" << endl;
else
cout << "var != value" << endl;
var = value;
}
};
int main() {
C c1;
C c2;
c1.Test(100);
c2.Test(100);
}
var != value
var == value
A partir do C++11, uma inicialização de static variável local tem a garantia de ser thread-safe. Este recurso é às vezes chamado de estática mágica. No entanto, em um aplicativo multithreaded, todas as atribuições subsequentes devem ser sincronizadas. O recurso de inicialização estática thread-safe pode ser desativado usando o /Zc:threadSafeInit- sinalizador para evitar uma dependência do CRT.
extern
Objetos e variáveis declarados como extern declaram um objeto que é definido em outra unidade de tradução ou em um escopo de inclusão como tendo ligação externa. Para obter mais informações, consulte extern e Unidades de tradução e vinculação.
thread_local (C++11)
Uma variável declarada com o thread_local especificador é acessível somente no thread no qual é criada. A variável é criada quando o thread é criado e é destruída quando o thread é destruído. Cada thread tem sua própria cópia da variável. No Windows, thread_local é funcionalmente equivalente ao atributo específico __declspec( thread ) da Microsoft.
thread_local float f = 42.0; // Global namespace. Not implicitly static.
struct S // cannot be applied to type definition
{
thread_local int i; // Illegal. The member must be static.
thread_local static char buf[10]; // OK
};
void DoSomething()
{
// Apply thread_local to a local variable.
// Implicitly "thread_local static S my_struct".
thread_local S my_struct;
}
Aspetos a ter em conta sobre o thread_local especificador:
Variáveis thread-local inicializadas dinamicamente em DLLs podem não ser inicializadas corretamente em todos os threads de chamada. Para obter mais informações, consulte
thread.O
thread_localespecificador pode ser combinado comstaticouextern.Você pode aplicar
thread_localapenas a declarações e definições de dados,thread_localnão pode ser usado em declarações ou definições de função.Você pode especificar
thread_localsomente em itens de dados com duração de armazenamento estático, o que inclui objetos de dados globais (ambosstaticeextern), objetos estáticos locais e membros de dados estáticos de classes. Qualquer variável local declaradathread_localé implicitamente estática se nenhuma outra classe de armazenamento for fornecida, ou seja, no escopothread_localdo bloco é equivalente athread_local static.Você deve especificar
thread_localpara a declaração e a definição de um objeto local de thread, se a declaração e a definição ocorrem no mesmo arquivo ou em arquivos separados.Não recomendamos que você use
thread_localvariáveis comstd::launch::async. Para obter mais informações, consulte<future>funções.
No Windows, thread_local é funcionalmente equivalente a __declspec(thread) exceto que *__declspec(thread)* pode ser aplicado a uma definição de tipo e é válido no código C. Sempre que possível, use thread_local porque faz parte do padrão C++ e, portanto, é mais portátil.
registo
Visual Studio 2017 versão 15.3 e posterior (disponível no /std:c++17 modo e posterior): A register palavra-chave não é mais uma classe de armazenamento suportada. Seu uso causa um diagnóstico. A palavra-chave ainda está reservada no padrão para uso futuro.
register int val; // warning C5033: 'register' is no longer a supported storage class
Exemplo: inicialização automática vs. estática
Um objeto ou variável automática local é inicializado toda vez que o fluxo de controle atinge sua definição. Um objeto estático local ou variável é inicializado na primeira vez que o fluxo de controle atinge sua definição.
Considere o exemplo a seguir, que define uma classe que registra a inicialização e a destruição de objetos e, em seguida, define três objetos, I1, I2e I3:
// initialization_of_objects.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;
// Define a class that logs initializations and destructions.
class InitDemo {
public:
InitDemo( const char *szWhat );
~InitDemo();
private:
char *szObjName;
size_t sizeofObjName;
};
// Constructor for class InitDemo
InitDemo::InitDemo( const char *szWhat ) :
szObjName(NULL), sizeofObjName(0) {
if ( szWhat != 0 && strlen( szWhat ) > 0 ) {
// Allocate storage for szObjName, then copy
// initializer szWhat into szObjName, using
// secured CRT functions.
sizeofObjName = strlen( szWhat ) + 1;
szObjName = new char[ sizeofObjName ];
strcpy_s( szObjName, sizeofObjName, szWhat );
cout << "Initializing: " << szObjName << "\n";
}
else {
szObjName = 0;
}
}
// Destructor for InitDemo
InitDemo::~InitDemo() {
if( szObjName != 0 ) {
cout << "Destroying: " << szObjName << "\n";
delete szObjName;
}
}
// Enter main function
int main() {
InitDemo I1( "Auto I1" ); {
cout << "In block.\n";
InitDemo I2( "Auto I2" );
static InitDemo I3( "Static I3" );
}
cout << "Exited block.\n";
}
Initializing: Auto I1
In block.
Initializing: Auto I2
Initializing: Static I3
Destroying: Auto I2
Exited block.
Destroying: Auto I1
Destroying: Static I3
Este exemplo demonstra como e quando os objetos I1, I2, e I3 são inicializados e quando são destruídos.
Há vários pontos a observar sobre o programa:
Primeiro,
I1eI2são automaticamente destruídos quando o fluxo de controle sai do bloco no qual eles estão definidos.Em segundo lugar, em C++, não é necessário declarar objetos ou variáveis no início de um bloco. Além disso, esses objetos são inicializados somente quando o fluxo de controle atinge suas definições.
I2( eI3são exemplos de tais definições.) A saída mostra exatamente quando eles são inicializados.Finalmente, variáveis locais estáticas, como
I3reter seus valores enquanto o programa é executado, mas são destruídas quando o programa termina.