字符串 s; &s+1;合法的?布?
考虑以下代码:
#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]
指向不等于 5 的值存在;数组中的第六元素。上面的代码中还有另一个例子:myVec.end()
,它指向向量myVec
的末尾一位。获取这个不存在的元素的地址是完全合法的。我们知道string
的大小,因此我们知道C风格string
数组的第6个元素的地址必须指向哪里。只要我们只计算这个指针而不取消引用它,就可以了。我们甚至可以将它与其他指针进行比较以获得相等性。 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
也是一个数组?
Consider the following code:
#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;
}
Of interest here is &myAry[numStrs]
: numStrs is equal to 5, so &myAry[numStrs]
points to something that doesn't exist; the sixth element in the array. There is another example of this in the above code: myVec.end()
, which points to one-past-the-end of the vector myVec
. It's perfecly legal to take the address of this element that doesn't exist. We know the size of string
, so we know where the address of the 6th element of a C-style array of string
s must point to. So long as we only evaluate this pointer and never dereference it, we're fine. We can even compare it to other pointers for equality. The STL does this all the time in algorithms that act on a range of iterators. The end()
iterator points past the end, and the loops keep looping while a counter != end()
.
So now consider this:
#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;
}
Is this code legal and well-defined? It is legal and well-defined to take the address of an array element past the end, as in &myAry[numStrs]
, so should it be legal and well-defined to pretend that myPtr
is also an array?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
拥有一个指向数组“超出末尾”的指针是合法的,而不是 UB,并且任何单个对象都可以被视为位于长度为 1 的数组中;但是,由于
&ptr[1]
取消引用然后获取地址的技术性,您需要使用ptr + 1
来代替。这也适用于&array[size]
变为array + size
。您所拥有的将在我所知道的所有平台上按照您的预期工作,但考虑到使用明确正确的形式是多么容易,我认为没有理由不这样做。
It is legal and not UB to have a pointer to "one past the end" of an array, and any single object can be treated as if it were in an array of length 1; however, you need to use
ptr + 1
instead due to the technicality of&ptr[1]
dereferencing and then taking the address. This also applies to&array[size]
becomingarray + size
.What you have will work as you expect on all platforms of which I'm aware, but given how easy it is to use the unambiguously correct form, I see no reason not to do that instead.
C++标准5.6/4“加法运算符”中说:
C99 标准 6.5.6/7 的说法基本相同。
The C++ standard in 5.6/4 "Additive operators" says:
The C99 standard 6.5.6/7 says essentially the same.