Рассмотрим следующий код:
#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;
}
Здесь представляет интерес &myAry[numStrs]
: numStrs равно 5, поэтому &myAry[numStrs]
указывает на то, чего не существует; шестой элемент в массиве. В приведенном выше коде есть еще один пример: myVec.end()
, который указывает на один конец вектора myVec
. Совершенно законно взять адрес несуществующего элемента. Мы знаем размер string
, поэтому мы знаем, куда должен указывать адрес 6-го элемента массива string
s в стиле C. Пока мы только оцениваем этот указатель и никогда не разыменовываем его, все в порядке. Мы даже можем сравнить его с другими указателями на равенство. STL делает это все время в алгоритмах, которые работают с рядом итераторов. Итератор end()
указывает на конец, и циклы продолжают повторяться, пока счетчик != end()
.
Итак, теперь подумайте об этом:
#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;
}
Является ли этот код законным и четко определенным? Допустимо и четко определено брать адрес элемента массива после конца, как в &myAry[numStrs]
, поэтому должно ли быть законно и четко определено делать вид, что myPtr
также является массивом?