cordas; & S + 1; Legal? UB?
-
18-09-2019 - |
Pergunta
Considere o seguinte código:
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string myAry[] =
{
"Mary",
"had",
"a",
"Little",
"Lamb"
};
const size_t numStrs = sizeof(myStr)/sizeof(myAry[0]);
vector<string> myVec(&myAry[0], &myAry[numStrs]);
copy( myVec.begin(), myVec.end(), ostream_iterator<string>(cout, " "));
return 0;
}
De interesse aqui é &myAry[numStrs]
: numStrs é igual a 5, de modo &myAry[numStrs]
aponta para algo que não existe; sexto elemento na matriz. Há um outro exemplo deste no código acima: myVec.end()
, o que aponta para um passado-a-extremidade do myVec
vector. É perfecly legal para tomar o endereço deste elemento que não existe. Sabemos o tamanho da string
, por isso sabemos onde o endereço da 6ª elemento de uma matriz C-estilo de string
s deve apontar para. Enquanto nós só avaliar este ponteiro e nunca desreferenciava isso, estamos bem. Podemos até compará-lo com outros ponteiros para a igualdade. O STL faz isso o tempo todo em algoritmos que agem sobre uma gama de iteradores. Os pontos end()
iteradoras últimos final, e os loops manter looping enquanto um contador != end()
.
Agora considere o seguinte:
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string myStr = "Mary";
string* myPtr = &myStr;
vector<string> myVec2(myPtr, &myPtr[1]);
copy( myVec2.begin(), myVec2.end(), ostream_iterator<string>(cout, " "));
return 0;
}
É este código legal e bem definida? É legal e bem definido para obter o endereço de um elemento de matriz após o final, como em &myAry[numStrs]
, por isso deve ser legal e bem definido para fingir que myPtr
é também um array?
Solução
é legal e não UB ter um ponteiro de "um após o final" de uma matriz, e um único objecto pode ser tratada como se fosse em uma matriz de um comprimento; no entanto, você precisa usar ptr + 1
vez devido à tecnicidade da dereferencing &ptr[1]
e, em seguida, tomando o endereço. Isso também se aplica a &array[size]
tornando array + size
.
O que você tem vai funcionar como você espera em todas as plataformas do qual eu estou ciente, mas dado o quão fácil é de usar a forma inequivocamente correta, não vejo razão para não fazer isso em seu lugar.
Outras dicas
O padrão C ++ em 5,6 / 4 "operadores aditivos" diz:
Para efeitos destes operadores, um apontador para um objecto nonarray se comporta da mesma como um ponteiro para o primeiro elemento de uma matriz de um comprimento com o tipo do objecto como o seu tipo de elemento.
A norma 6.5.6 / 7 C99 diz essencialmente o mesmo.