O maior problema em ter matrizes marcadas com seu comprimento não é tanto o espaço necessário para armazenar esse tamanho, nem a questão de como ele deve ser armazenado (usar um byte extra para matrizes curtas geralmente não seria censurável, nem iria usar quatro bytes extras para matrizes longas, mas usando quatro bytes, mesmo para matrizes curtas pode ser). Um problema muito maior é que determinado código como:
void ClearTwoElements(int *ptr)
{
ptr[-2] = 0;
ptr[2] = 0;
}
void blah(void)
{
static int foo[10] = {1,2,3,4,5,6,7,8,9,10};
ClearTwoElements(foo+2);
ClearTwoElements(foo+7);
ClearTwoElements(foo+1);
ClearTwoElements(foo+8);
}
a única maneira de o código aceitar a primeira chamada para ClearTwoElements
, mas rejeitar a segunda, seria para o método ClearTwoElements
receber informações suficientes para saber que, em cada caso, recebia uma referência a parte de o array foo
além de saber qual parte. Isso normalmente dobraria o custo de passar parâmetros de ponteiro. Além disso, se cada matriz foi precedida por um ponteiro para um endereço logo após o final (o formato mais eficiente para validação), o código otimizado para ClearTwoElements
provavelmente se tornaria algo como:
void ClearTwoElements(int *ptr)
{
int* array_end = ARRAY_END(ptr);
if ((array_end - ARRAY_BASE(ptr)) < 10 ||
(ARRAY_BASE(ptr)+4) <= ADDRESS(ptr) ||
(array_end - 4) < ADDRESS(ptr)))
trap();
*(ADDRESS(ptr) - 4) = 0;
*(ADDRESS(ptr) + 4) = 0;
}
Note que um chamador de método poderia, em geral, passar legitimamente um ponteiro para o início da matriz ou o último elemento para um método; somente se o método tentar acessar elementos que estão fora da matriz transmitida, esses indicadores causarão algum problema. Conseqüentemente, um método chamado teria que primeiro garantir que o array fosse grande o suficiente para que a aritmética do ponteiro para validar seus argumentos não saísse dos limites e fizesse alguns cálculos de ponteiro para validar os argumentos. O tempo gasto em tal validação provavelmente excederia o custo gasto com qualquer trabalho real. Além disso, o método provavelmente seria mais eficiente se fosse escrito e chamado:
void ClearTwoElements(int arr[], int index)
{
arr[index-2] = 0;
arr[index+2] = 0;
}
void blah(void)
{
static int foo[10] = {1,2,3,4,5,6,7,8,9,10};
ClearTwoElements(foo,2);
ClearTwoElements(foo,7);
ClearTwoElements(foo,1);
ClearTwoElements(foo,8);
}
O conceito de um tipo que combina algo para identificar um objeto com algo para identificar uma parte dele é bom. Um ponteiro no estilo C é mais rápido, no entanto, se não for necessário realizar a validação.