2010-03-08 31 views
5

Xét đoạn mã sau:chuỗi s; &s+1; Pháp lý? UB?

#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; 
} 

Quan tâm ở đây là &myAry[numStrs]: numStrs bằng 5, do &myAry[numStrs] điểm đến cái gì đó không tồn tại; phần tử thứ sáu trong mảng. Có một ví dụ khác về điều này trong đoạn mã trên: myVec.end(), trỏ đến một đầu-cuối của véc tơ myVec. Thật là hợp pháp về mặt pháp lý để lấy địa chỉ của yếu tố này không tồn tại. Chúng tôi biết kích thước của string, vì vậy chúng tôi biết địa chỉ của phần tử thứ 6 của mảng kiểu C là string phải trỏ đến. Vì vậy, miễn là chúng tôi chỉ đánh giá con trỏ này và không bao giờ dereference nó, chúng tôi đang tốt. Chúng ta thậm chí có thể so sánh nó với các con trỏ khác để bình đẳng. STL thực hiện điều này mọi lúc trong các thuật toán hoạt động trên một loạt các trình lặp. Các điểm vòng lặp end() lặp lại kết thúc và các vòng lặp giữ vòng lặp trong khi bộ đếm != end().

Bây giờ xem xét việc này:

#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; 
} 

là mã này quy phạm pháp luật và được xác định rõ? Đó là hợp pháp và được xác định rõ ràng để lấy địa chỉ của một phần tử mảng qua cuối, như trong &myAry[numStrs], do đó, nó nên được hợp pháp và được xác định rõ ràng để giả vờ rằng myPtr cũng là một mảng?

Trả lời

12

Điều này là hợp pháp và không phải UB có con trỏ đến "một trong quá khứ" của một mảng và bất kỳ đối tượng nào có thể được xử lý như thể nó nằm trong một mảng có độ dài 1; tuy nhiên, bạn cần phải sử dụng ptr + 1 thay vì do tính kỹ thuật của &ptr[1] dereferencing và sau đó lấy địa chỉ. Điều này cũng áp dụng cho &array[size] trở thành array + size.

Những gì bạn có sẽ hoạt động như bạn mong đợi trên tất cả các nền tảng mà tôi biết, nhưng việc sử dụng biểu mẫu chính xác dễ dàng đến mức nào, tôi không thấy lý do nào để không làm điều đó thay thế.

+8

+1 cho độ chính xác kỹ thuật. Không chỉ dễ dàng để làm điều đó đúng, nhưng nó cũng tránh những cạm bẫy hơn nữa với 'toán tử &' đang bị quá tải (nó quá tệ để quá tải nó, vâng. Nhưng điều này cho thấy cách người ta chỉ kéo phụ thuộc vào). Tốt nhất để tránh được hành vi không xác định. –

5

C++ tiêu chuẩn trong 5.6/4 "nhà khai thác Additive" nói:

Theo mục đích của các nhà khai thác, một con trỏ đến một đối tượng nonarray cư xử giống như một con trỏ đến phần tử đầu tiên của một mảng của chiều dài một với loại đối tượng là loại phần tử của nó.

Tiêu chuẩn C99 6.5.6/7 nói về cơ bản giống nhau.

Các vấn đề liên quan