C ++ herdou matrizes de C, onde são usadas praticamente em qualquer lugar. C ++ fornece abstrações que são mais fáceis de usar e menos propenso a erros ( std::vector<T>
desde C ++ 98 e std::array<T, n>
desde C ++ 11 ), de modo que a necessidade de matrizes não surge tão frequentemente como faz em C. No entanto, quando você lê legado codificar ou interagir com uma biblioteca escrita em C, você deve ter uma noção firme de como as matrizes funcionam.
Este FAQ está dividido em cinco partes:
- matrizes no nível de tipo e elementos de acesso
- criação e inicialização de array
- atribuição e passagem de parâmetros
- matrizes multidimensionais e matrizes de ponteiros
- armadilhas comuns ao usar matrizes
Se você sentir que algo importante está faltando nesta FAQ, escreva uma resposta e vincule-a aqui como uma parte adicional.
No texto a seguir, "matriz" significa "matriz C", não o modelo de classe std::array
. O conhecimento básico da sintaxe do declarador C é assumido. Observe que o uso manual de new
e delete
como demonstrado abaixo é extremamente perigoso diante de exceções, mas esse é o tópico de outra FAQ .
(Observação: isso deve ser uma entrada para as Perguntas frequentes sobre C ++ do Stack Overflow . Se você quiser criticar a idéia de fornecer uma FAQ neste formulário, a postagem na meta que iniciou tudo isso seria o lugar para isso. essa pergunta é monitorada na sala de bate-papo do C ++ , onde a ideia das Perguntas frequentes começou em primeiro lugar; portanto, é muito provável que sua resposta seja lida por quem a teve.)
std::array
s,std::vector
s egsl::span
s - Eu francamente esperar um FAQ sobre como usar matrizes em C ++ para dizer "Até agora, você pode começar a considerar que, bem, não usá-los."Respostas:
Matrizes no nível de tipo
Um tipo de matriz é indicado como
T[n]
ondeT
está o tipo de elemento en
é um tamanho positivo , o número de elementos na matriz. O tipo de matriz é um tipo de produto do tipo de elemento e do tamanho. Se um ou ambos os ingredientes diferirem, você obtém um tipo distinto:Observe que o tamanho faz parte do tipo, ou seja, tipos de matriz de tamanho diferente são tipos incompatíveis que não têm absolutamente nada a ver um com o outro.
sizeof(T[n])
é equivalente an * sizeof(T)
.Decaimento de matriz para ponteiro
A única "conexão" entre
T[n]
eT[m]
é que ambos os tipos podem ser implicitamente convertidos emT*
, e o resultado dessa conversão é um ponteiro para o primeiro elemento da matriz. Ou seja, em qualquer lugar queT*
seja necessário, você pode fornecer umT[n]
e o compilador silenciosamente fornecerá esse ponteiro:Essa conversão é conhecida como "decaimento de matriz para ponteiro" e é uma importante fonte de confusão. O tamanho da matriz é perdido nesse processo, pois não faz mais parte do tipo (
T*
). Pro: esquecer o tamanho de uma matriz no nível de tipo permite que um ponteiro aponte para o primeiro elemento de uma matriz de qualquer tamanho. Con: dado um ponteiro para o primeiro (ou qualquer outro) elemento de uma matriz, não há como detectar o tamanho dessa matriz ou para onde exatamente o ponteiro aponta em relação aos limites da matriz. Os ponteiros são extremamente estúpidos .Matrizes não são ponteiros
O compilador silenciosamente irá gerar um ponteiro para o primeiro elemento de uma matriz sempre que for considerado útil, ou seja, sempre que uma operação falhar em uma matriz, mas for bem-sucedida em um ponteiro. Essa conversão de matriz para ponteiro é trivial, pois o valor resultante do ponteiro é simplesmente o endereço da matriz. Observe que o ponteiro não é armazenado como parte da própria matriz (ou em qualquer outro lugar na memória). Uma matriz não é um ponteiro.
Um contexto importante em que uma matriz não se decompõe em um ponteiro para seu primeiro elemento é quando o
&
operador é aplicado a ela. Nesse caso, o&
operador gera um ponteiro para toda a matriz, não apenas um ponteiro para o primeiro elemento. Embora nesse caso os valores (os endereços) sejam os mesmos, um ponteiro para o primeiro elemento de uma matriz e um ponteiro para toda a matriz são tipos completamente distintos:A seguinte arte ASCII explica essa distinção:
Observe como o ponteiro para o primeiro elemento aponta apenas para um único número inteiro (representado como uma caixa pequena), enquanto o ponteiro para a matriz inteira aponta para uma matriz de 8 números inteiros (representados como uma caixa grande).
A mesma situação surge nas aulas e é talvez mais óbvia. Um ponteiro para um objeto e um ponteiro para seu primeiro membro de dados têm o mesmo valor (o mesmo endereço), mas são tipos completamente distintos.
Se você não estiver familiarizado com a sintaxe do declarador C, os parênteses no tipo
int(*)[8]
são essenciais:int(*)[8]
é um ponteiro para uma matriz de 8 números inteiros.int*[8]
é uma matriz de 8 pontos, cada elemento do tipoint*
.Acessando elementos
O C ++ fornece duas variações sintáticas para acessar elementos individuais de uma matriz. Nenhum deles é superior ao outro, e você deve se familiarizar com os dois.
Aritmética do ponteiro
Dado um ponteiro
p
para o primeiro elemento de uma matriz, a expressãop+i
gera um ponteiro para o i-ésimo elemento da matriz. Ao remover a referência desse ponteiro posteriormente, é possível acessar elementos individuais:Se
x
denota uma matriz , o decaimento da matriz para o ponteiro entra em ação, porque adicionar uma matriz e um número inteiro não faz sentido (não há mais operação nas matrizes), mas a adição de um ponteiro e um número inteiro faz sentido:(Observe que o ponteiro gerado implicitamente não tem nome, então escrevi
x+0
para identificá-lo.)Se, por outro lado,
x
denota um ponteiro para o primeiro (ou qualquer outro) elemento de uma matriz, o decaimento de matriz para ponteiro não é necessário, porque o ponteiro ao quali
será adicionado já existe:Observe que, no caso representado,
x
é uma variável de ponteiro (discernível pela caixa pequena ao lado dex
), mas também poderia ser o resultado de uma função retornando um ponteiro (ou qualquer outra expressão do tipoT*
).Operador de indexação
Como a sintaxe
*(x+i)
é um pouco desajeitada, o C ++ fornece a sintaxe alternativax[i]
:Devido ao fato da adição ser comutativa, o código a seguir faz exatamente o mesmo:
A definição do operador de indexação leva à seguinte equivalência interessante:
No entanto,
&x[0]
geralmente não é equivalente ax
. O primeiro é um ponteiro, o segundo uma matriz. Somente quando o contexto dispara a deterioração da matriz para o ponteiro podex
e pode&x[0]
ser usado de forma intercambiável. Por exemplo:Na primeira linha, o compilador detecta uma atribuição de um ponteiro para um ponteiro, o que é trivialmente bem-sucedido. Na segunda linha, ele detecta uma atribuição de uma matriz para um ponteiro. Uma vez que este é o sentido (mas ponteiro para atribuição ponteiro faz sentido), pontapés decaimento matriz-a-ponteiro em como de costume.
Gamas
Uma matriz do tipo
T[n]
possuin
elementos indexados de0
paran-1
; não há nenhum elementon
. E, no entanto, para oferecer suporte a intervalos semi-abertos (onde o começo é inclusivo e o final é exclusivo ), o C ++ permite o cálculo de um ponteiro para o n-ésimo elemento (inexistente), mas é ilegal desreferenciar esse ponteiro:Por exemplo, se você deseja classificar uma matriz, os dois itens a seguir funcionam igualmente bem:
Observe que é ilegal fornecer
&x[n]
como o segundo argumento, já que isso é equivalente a&*(x+n)
, e a subexpressão*(x+n)
invoca tecnicamente um comportamento indefinido em C ++ (mas não em C99).Observe também que você pode simplesmente fornecer
x
como o primeiro argumento. Isso é um pouco conciso demais para o meu gosto e também torna a dedução do argumento do modelo um pouco mais difícil para o compilador, porque nesse caso o primeiro argumento é uma matriz, mas o segundo argumento é um ponteiro. (Novamente, a deterioração da matriz para o ponteiro entra em ação.)fonte
Os programadores geralmente confundem matrizes multidimensionais com matrizes de ponteiros.
Matrizes multidimensionais
Muitos programadores estão familiarizados com as matrizes multidimensionais nomeadas, mas muitos desconhecem o fato de que a matriz multidimensional também pode ser criada anonimamente. Matrizes multidimensionais são frequentemente chamadas de "matrizes de matrizes" ou " matrizes multidimensionais verdadeiras ".
Matrizes multidimensionais nomeadas
Ao usar matrizes multidimensionais nomeadas, todas as dimensões devem ser conhecidas no momento da compilação:
É assim que uma matriz multidimensional denominada se parece na memória:
Observe que as grades 2D, como as anteriores, são apenas visualizações úteis. Do ponto de vista do C ++, a memória é uma sequência "plana" de bytes. Os elementos de uma matriz multidimensional são armazenados na ordem principal da linha. Ou seja,
connect_four[0][6]
econnect_four[1][0]
são vizinhos na memória. De fato,connect_four[0][7]
econnect_four[1][0]
denotam o mesmo elemento! Isso significa que você pode pegar matrizes multidimensionais e tratá-las como matrizes unidimensionais grandes:Matrizes multidimensionais anônimas
Com matrizes multidimensionais anônimas, todas as dimensões, exceto a primeira, devem ser conhecidas em tempo de compilação:
É assim que uma matriz multidimensional anônima se parece na memória:
Observe que o próprio array ainda está alocado como um único bloco na memória.
Matrizes de ponteiros
Você pode superar a restrição de largura fixa introduzindo outro nível de indireção.
Matrizes nomeadas de ponteiros
Aqui está uma matriz nomeada de cinco ponteiros que são inicializados com matrizes anônimas de diferentes comprimentos:
E aqui está como fica na memória:
Como cada linha é alocada individualmente agora, visualizar matrizes 2D como matrizes 1D não funciona mais.
Matrizes anônimas de ponteiros
Aqui está uma matriz anônima de 5 (ou qualquer outro número de) ponteiros que são inicializados com matrizes anônimas de diferentes comprimentos:
E aqui está como fica na memória:
Conversões
A deterioração de matriz para ponteiro se estende naturalmente a matrizes de matrizes e matrizes de ponteiros:
No entanto, não há conversão implícita de
T[h][w]
paraT**
. Se tal conversão implícita existisse, o resultado seria um ponteiro para o primeiro elemento de uma matriz deh
ponteiros paraT
(cada um apontando para o primeiro elemento de uma linha na matriz 2D original), mas essa matriz de ponteiros não existe em nenhum lugar memória ainda. Se você deseja essa conversão, deve criar e preencher manualmente a matriz de ponteiros necessária:Observe que isso gera uma visão da matriz multidimensional original. Se você precisar de uma cópia, crie matrizes extras e copie os dados:
fonte
int connect_four[H][7];
,int connect_four[6][W];
int connect_four[H][W];
assim comoint (*p)[W] = new int[6][W];
eint (*p)[W] = new int[H][W];
são declarações válidas, quandoH
eW
são conhecidas em tempo de compilação.Tarefa
Por nenhum motivo específico, as matrizes não podem ser atribuídas uma à outra. Use em
std::copy
vez disso:Isso é mais flexível do que o que a verdadeira atribuição de matriz poderia fornecer porque é possível copiar fatias de matrizes maiores em matrizes menores.
std::copy
geralmente é especializado em tipos primitivos para oferecer desempenho máximo. É improvável que tenha umstd::memcpy
desempenho melhor. Em caso de dúvida, meça.Embora você não possa atribuir matrizes diretamente, é possível atribuir estruturas e classes que contêm membros da matriz. Isso ocorre porque os membros da matriz são copiados membro a membro pelo operador de atribuição, que é fornecido como padrão pelo compilador. Se você definir o operador de atribuição manualmente para seus próprios tipos de estrutura ou classe, deverá voltar à cópia manual para os membros da matriz.
Passagem de parâmetro
Matrizes não podem ser passadas por valor. Você pode passá-los por ponteiro ou por referência.
Passe pelo ponteiro
Como as próprias matrizes não podem ser passadas por valor, geralmente um ponteiro para o primeiro elemento é passado por valor. Isso geralmente é chamado de "passar pelo ponteiro". Como o tamanho da matriz não é recuperável por meio desse ponteiro, é necessário passar um segundo parâmetro indicando o tamanho da matriz (a solução C clássica) ou um segundo ponteiro apontando após o último elemento da matriz (a solução do iterador C ++) :
Como alternativa sintática, você também pode declarar parâmetros como
T p[]
e significa exatamente a mesma coisa que apenasT* p
no contexto das listas de parâmetros :Você pode pensar no compilador como reescrever
T p[]
aT *p
no contexto de apenas listas de parâmetros . Essa regra especial é parcialmente responsável por toda a confusão sobre matrizes e ponteiros. Em qualquer outro contexto, declarar algo como uma matriz ou como um ponteiro faz uma enorme diferença.Infelizmente, você também pode fornecer um tamanho em um parâmetro de matriz que é ignorado silenciosamente pelo compilador. Ou seja, as três assinaturas a seguir são exatamente equivalentes, conforme indicado pelos erros do compilador:
Passe por referência
As matrizes também podem ser passadas por referência:
Nesse caso, o tamanho da matriz é significativo. Como escrever uma função que aceita apenas matrizes de exatamente 8 elementos é de pouca utilidade, os programadores geralmente escrevem funções como modelos:
Observe que você só pode chamar esse modelo de função com uma matriz real de números inteiros, não com um ponteiro para um número inteiro. O tamanho da matriz é inferido automaticamente e, para cada tamanho
n
, uma função diferente é instanciada no modelo. Você também pode escrever modelos de função bastante úteis que abstraem do tipo de elemento e do tamanho.fonte
void foo(int a[3])
a
que pareça estar passando a matriz por valor, a modificaçãoa
interna defoo
modificará a matriz original. Isso deve ficar claro, porque as matrizes não podem ser copiadas, mas pode valer a pena reforçar isso.ranges::copy(a, b)
int sum( int size_, int a[size_]);
- a partir de (eu acho) C99 em diante5. Armadilhas comuns ao usar matrizes.
5.1 Armadilha: Confiando em links não seguros do tipo.
OK, você foi informado ou descobriu que globals (variáveis de escopo de namespace que podem ser acessadas fora da unidade de tradução) são Evil ™. Mas você sabia como eles são realmente maus? Considere o programa abaixo, composto por dois arquivos [main.cpp] e [numbers.cpp]:
No Windows 7, isso compila e vincula bem ao MinGW g ++ 4.4.1 e ao Visual C ++ 10.0.
Como os tipos não correspondem, o programa falha quando você o executa.
Explicação formal: o programa tem comportamento indefinido (UB) e, em vez de travar, pode simplesmente travar, ou talvez não fazer nada, ou enviar e-mails ameaçadores aos presidentes dos EUA, Rússia, Índia, China e Suíça, e faça com que os Daemons Nasais voem pelo nariz.
Explicação na prática: na
main.cpp
matriz é tratada como um ponteiro, colocado no mesmo endereço da matriz. Para executável de 32 bits, isso significa que o primeiroint
valor na matriz é tratado como um ponteiro. Isto é,main.cpp
nanumbers
variável contém, ou parece conter,(int*)1
. Isso faz com que o programa acesse a memória na parte inferior do espaço de endereço, que é convencionalmente reservado e causa trapping. Resultado: você recebe um acidente.Os compiladores têm pleno direito de não diagnosticar esse erro, porque C ++ 11 §3.5 / 10 diz sobre o requisito de tipos compatíveis para as declarações,
O mesmo parágrafo detalha a variação permitida:
Essa variação permitida não inclui declarar um nome como uma matriz em uma unidade de tradução e como um ponteiro em outra unidade de tradução.
5.2 Armadilha: Fazendo otimização prematura (
memset
e amigos).Ainda não escrito
5.3 Armadilha: Usando o idioma C para obter o número de elementos.
Com profunda experiência em C, é natural escrever…
Como um
array
decaimento para apontar para o primeiro elemento, quando necessário, a expressãosizeof(a)/sizeof(a[0])
também pode ser escrita comosizeof(a)/sizeof(*a)
. Significa o mesmo, e não importa como está escrito, é o idioma C para encontrar os elementos numéricos da matriz.Armadilha principal: o idioma C não é seguro. Por exemplo, o código…
passa um ponteiro para
N_ITEMS
e, portanto, provavelmente produz um resultado errado. Compilado como um executável de 32 bits no Windows 7, produz…int const a[7]
para apenasint const a[]
.int const a[]
paraint const* a
.N_ITEMS
é, portanto, invocado com um ponteiro.sizeof(array)
(tamanho de um ponteiro) é então 4.sizeof(*array)
é equivalente asizeof(int)
, que para um executável de 32 bits também é 4.Para detectar esse erro no tempo de execução, você pode…
A detecção de erros em tempo de execução é melhor do que nenhuma detecção, mas desperdiça um pouco de tempo do processador e talvez muito mais tempo do programador. Melhor com detecção em tempo de compilação! E se você estiver feliz por não suportar matrizes de tipos locais com C ++ 98, poderá fazer isso:
Compilando essa definição substituída no primeiro programa completo, com g ++, obtive…
Como funciona: a matriz é passada por referência e
n_items
, portanto, não se deteriora para apontar para o primeiro elemento, e a função pode simplesmente retornar o número de elementos especificado pelo tipo.Com o C ++ 11, você também pode usá-lo para matrizes do tipo local, e é o idioma C ++ seguro para encontrar o número de elementos de uma matriz.
5.4 Armadilha C ++ 11 e C ++ 14: Usando uma
constexpr
função de tamanho de matriz.Com o C ++ 11 e posterior, é natural, mas como você verá perigoso !, substituir a função C ++ 03
com
onde a mudança significativa é o uso de
constexpr
, que permite que essa função produza uma constante de tempo de compilação .Por exemplo, em contraste com a função C ++ 03, essa constante de tempo de compilação pode ser usada para declarar uma matriz do mesmo tamanho que outra:
Mas considere este código usando a
constexpr
versão:A armadilha: em julho de 2015, o acima foi compilado com o MinGW-64 5.1.0 com
C ++ 11 C ++ 14 $ 5,19 / 2 de nove th traço-pedantic-errors
, e testando com os compiladores on-line em gcc.godbolt.org/ , também com o clang 3.0 e o clang 3.2, mas não com o clang 3.3, 3.4. 1, 3.5.0, 3.5.1, 3.6 (rc1) ou 3.7 (experimental). E importante para a plataforma Windows, ele não é compilado com o Visual C ++ 2015. O motivo é uma instrução C ++ 11 / C ++ 14 sobre o uso de referências emconstexpr
expressões:Pode-se sempre escrever o mais detalhado
… Mas isso falha quando
Collection
não é uma matriz bruta.Para lidar com coleções que podem ser não matrizes, é necessário sobrecarregar uma
n_items
função, mas também, para uso em tempo de compilação, é necessário uma representação em tempo de compilação do tamanho da matriz. E a solução clássica C ++ 03, que também funciona bem em C ++ 11 e C ++ 14, é permitir que a função relate seu resultado não como um valor, mas por meio do tipo de resultado da função . Por exemplo, assim:Sobre a escolha do tipo de retorno para
static_n_items
: este código não usastd::integral_constant
porque comstd::integral_constant
o resultado é representado diretamente como umconstexpr
valor, reintroduzindo o problema original. Em vez de umaSize_carrier
classe, pode-se deixar que a função retorne diretamente uma referência a uma matriz. No entanto, nem todo mundo está familiarizado com essa sintaxe.Sobre a nomeação: parte desta solução para o problema
constexpr
-invalid devido à referência é tornar explícita a escolha do tempo de compilação constante.Esperamos que o oops - houve uma referência envolvida no seu
constexpr
problema - seja corrigido com o C ++ 17, mas até então uma macro como aSTATIC_N_ITEMS
acima gera portabilidade, por exemplo, para os compiladores clang e Visual C ++, mantendo o tipo segurança.Relacionado: macros não respeitam escopos, portanto, para evitar colisões de nomes, pode ser uma boa ideia usar um prefixo de nome, por exemplo
MYLIB_STATIC_N_ITEMS
.fonte
Segmentation fault
... Finalmente descobri / entendi depois de ler suas explicações! Por favor, escreva sua seção §5.2 :-) Cheerssize_t
isso, não tenho vantagens que conheço para plataformas modernas, mas há vários problemas devido às regras implícitas de conversão de tipos de C e C ++. Ou seja,ptrdiff_t
é usado de forma muito intencional, para evitar os problemas comsize_t
. No entanto, deve-se estar ciente de que o g ++ tem um problema com a correspondência do tamanho da matriz com o parâmetro do modelo, a menos que sejasize_t
(não acho que esse problema específico do compilador com nãosize_t
seja importante, mas com o YMMV).size_t
para indicar tamanhos de matrizes, é claro que não.Criação e inicialização de matrizes
Como em qualquer outro tipo de objeto C ++, as matrizes podem ser armazenadas diretamente nas variáveis nomeadas (o tamanho deve ser uma constante em tempo de compilação; o C ++ não suporta VLAs ) ou podem ser armazenadas anonimamente na pilha e acessadas indiretamente via ponteiros (somente então o tamanho pode ser calculado em tempo de execução).
Matrizes automáticas
Matrizes automáticas (matrizes que vivem "na pilha") são criadas sempre que o fluxo de controle passa pela definição de uma variável de matriz local não estática:
A inicialização é realizada em ordem crescente. Observe que os valores iniciais dependem do tipo de elemento
T
:T
for um POD (comoint
no exemplo acima), nenhuma inicialização ocorrerá.T
inicializa todos os elementos.T
não fornecer um construtor padrão acessível, o programa não será compilado.Como alternativa, os valores iniciais podem ser especificados explicitamente no inicializador da matriz , uma lista separada por vírgulas, entre colchetes:
Como nesse caso o número de elementos no inicializador da matriz é igual ao tamanho da matriz, a especificação manual do tamanho é redundante. Ele pode ser deduzido automaticamente pelo compilador:
Também é possível especificar o tamanho e fornecer um inicializador de matriz mais curto:
Nesse caso, os elementos restantes são inicializados com zero . Observe que o C ++ permite um inicializador de matriz vazio (todos os elementos são inicializados com zero), enquanto o C89 não (pelo menos um valor é necessário). Observe também que os inicializadores de matriz podem ser usados apenas para inicializar matrizes; eles não podem mais tarde ser usados em atribuições.
Matrizes estáticas
Matrizes estáticas (matrizes que vivem "no segmento de dados") são variáveis de matriz locais definidas com a
static
palavra - chave e variáveis de matriz no escopo do espaço para nome ("variáveis globais"):(Observe que as variáveis no escopo do espaço para nome são implicitamente estáticas. Adicionar a
static
palavra-chave à sua definição tem um significado completamente diferente e obsoleto .)Aqui está como matrizes estáticas se comportam de maneira diferente das matrizes automáticas:
(Nenhuma das opções acima é específica para matrizes. Essas regras se aplicam igualmente bem a outros tipos de objetos estáticos.)
Membros de dados da matriz
Os membros de dados da matriz são criados quando o objeto de propriedade é criado. Infelizmente, o C ++ 03 não fornece meios para inicializar matrizes na lista de inicializadores de membros , portanto, a inicialização deve ser falsificada com atribuições:
Como alternativa, você pode definir uma matriz automática no corpo do construtor e copiar os elementos sobre:
No C ++ 0x, as matrizes podem ser inicializadas na lista de inicializadores de membros, graças à inicialização uniforme :
Essa é a única solução que funciona com tipos de elementos que não possuem construtor padrão.
Matrizes dinâmicas
Matrizes dinâmicas não têm nomes; portanto, o único meio de acessá-las é por meio de ponteiros. Como eles não têm nomes, vou me referir a eles como "matrizes anônimas" a partir de agora.
Em C, matrizes anônimas são criadas via
malloc
e amigos. No C ++, matrizes anônimas são criadas usando anew T[size]
sintaxe que retorna um ponteiro para o primeiro elemento de uma matriz anônima:A arte ASCII a seguir descreve o layout da memória se o tamanho for calculado como 8 em tempo de execução:
Obviamente, matrizes anônimas requerem mais memória que matrizes nomeadas devido ao ponteiro extra que deve ser armazenado separadamente. (Também há alguma sobrecarga adicional na loja gratuita.)
Observe que não há decaimento de matriz para ponteiro acontecendo aqui. Embora a avaliação
new int[size]
realmente crie uma matriz de números inteiros, o resultado da expressão jánew int[size]
é um ponteiro para um único número inteiro (o primeiro elemento), não uma matriz de números inteiros ou um ponteiro para uma matriz de números inteiros de tamanho desconhecido. Isso seria impossível, porque o sistema de tipo estático exige que os tamanhos de matriz sejam constantes em tempo de compilação. (Portanto, não anotei a matriz anônima com informações de tipo estático na imagem.)Em relação aos valores padrão para elementos, matrizes anônimas se comportam de maneira semelhante às matrizes automáticas. Normalmente, matrizes POD anônimas não são inicializadas, mas há uma sintaxe especial que aciona a inicialização de valor:
(Observe o par de parênteses à direita antes do ponto e vírgula.) Novamente, o C ++ 0x simplifica as regras e permite especificar valores iniciais para matrizes anônimas, graças à inicialização uniforme:
Se você terminar de usar uma matriz anônima, precisará liberá-la novamente para o sistema:
Você deve liberar cada matriz anônima exatamente uma vez e nunca mais tocá-la novamente. Não liberá-lo em todos os resultados em um vazamento de memória (ou mais geralmente, dependendo do tipo de elemento, um vazamento de recursos), e tentar liberá-lo várias vezes resulta em um comportamento indefinido. Usar o formulário não matriz
delete
(oufree
) em vez dedelete[]
liberar a matriz também é um comportamento indefinido .fonte
static
uso no escopo do espaço para nome foi removida no C ++ 11.new
ser um operador am, certamente poderia retornar a matriz allcated por referência. Simplesmente não faz sentido ...new
é muito mais antigo que as referências.int a[10]; int (&r)[] = a;