Theo nghĩa chặt chẽ nhất, đây không phải là Hành vi không xác định, mà là xác định do triển khai. Vì vậy, mặc dù không thích hợp nếu bạn có kế hoạch hỗ trợ các kiến trúc không chính thống, bạn có thể thể làm điều đó.
Trích dẫn tiêu chuẩn được đưa ra bởi interjay là một câu nói hay, chỉ ra UB, nhưng nó chỉ là tác phẩm hay thứ hai theo ý kiến của tôi, vì nó liên quan đến số học con trỏ con trỏ (một cách rõ ràng, một cái rõ ràng là UB, trong khi cái kia thì không). Có một đoạn liên quan đến hoạt động trong câu hỏi trực tiếp:
[expr.post.incr] / [expr.pre.incr]
Toán hạng sẽ là [...] hoặc một con trỏ tới loại đối tượng được xác định hoàn toàn.
Oh, đợi một lát, một loại đối tượng hoàn toàn xác định? Đó là tất cả? Ý tôi là, thực sự, loại ? Vì vậy, bạn không cần một đối tượng ở tất cả?
Phải mất khá nhiều thời gian để đọc thực sự tìm thấy một gợi ý rằng một cái gì đó trong đó có thể không được xác định rõ ràng. Bởi vì cho đến nay, nó đọc như thể bạn hoàn toàn được phép làm điều đó, không có hạn chế.
[basic.compound] 3
đưa ra tuyên bố về loại con trỏ mà người ta có thể có, và không phải là một trong ba loại kia, kết quả của hoạt động của bạn rõ ràng sẽ nằm dưới 3,4: con trỏ không hợp lệ .
Tuy nhiên, điều đó không nói rằng bạn không được phép có một con trỏ không hợp lệ. Ngược lại, nó liệt kê một số điều kiện rất phổ biến, thông thường (ví dụ: kết thúc thời gian lưu trữ) khi con trỏ thường xuyên trở nên không hợp lệ. Vì vậy, đó rõ ràng là một điều cho phép xảy ra. Và thực sự:
[basic.stc] 4 Chỉ định
thông qua một giá trị con trỏ không hợp lệ và chuyển một giá trị con trỏ không hợp lệ cho hàm thỏa thuận có hành vi không xác định. Bất kỳ việc sử dụng nào khác của giá trị con trỏ không hợp lệ đều có hành vi được xác định theo thực hiện.
Chúng tôi đang thực hiện "bất kỳ cái gì khác" ở đó, vì vậy nó không phải là Hành vi không xác định, nhưng được xác định theo triển khai, do đó thường được phép (trừ khi việc triển khai nói rõ ràng điều gì đó khác biệt).
Thật không may, đó không phải là kết thúc của câu chuyện. Mặc dù kết quả cuối cùng không thay đổi gì nữa kể từ đây, nhưng điều này càng gây nhầm lẫn, bạn càng tìm kiếm "con trỏ" lâu hơn:
[basic.compound]
Giá trị hợp lệ của loại con trỏ đối tượng biểu thị địa chỉ của một byte trong bộ nhớ hoặc con trỏ null. Nếu một đối tượng thuộc loại T được đặt tại một địa chỉ A [...] được cho là trỏ đến đối tượng đó, bất kể giá trị thu được như thế nào .
[Lưu ý: Chẳng hạn, địa chỉ nằm ở cuối một mảng sẽ được coi là trỏ đến một đối tượng không liên quan đến loại phần tử của mảng có thể nằm ở địa chỉ đó. [...]].
Đọc như: OK, ai quan tâm! Miễn là một con trỏ chỉ vào đâu đó trong bộ nhớ , tôi có tốt không?
[basic.stc.dynamic.safe] Giá trị con trỏ là con trỏ có nguồn gốc an toàn [blah blah]
Đọc như: OK, có nguồn gốc an toàn, bất cứ điều gì. Nó không giải thích điều này là gì, cũng không nói tôi thực sự cần nó. An toàn có nguồn gốc-the-heck. Rõ ràng tôi vẫn có thể có con trỏ không có nguồn gốc an toàn chỉ tốt. Tôi đoán rằng việc thảo luận lại có lẽ chúng không phải là một ý tưởng hay, nhưng nó hoàn toàn được phép có chúng. Nó không nói khác.
Việc triển khai có thể có an toàn con trỏ thoải mái, trong trường hợp đó tính hợp lệ của giá trị con trỏ không phụ thuộc vào việc nó có phải là giá trị con trỏ có nguồn gốc an toàn hay không.
Ồ, vậy nó có thể không quan trọng, chỉ là những gì tôi nghĩ. Nhưng chờ đã ... "có thể không"? Điều đó có nghĩa là, nó có thể là tốt . Làm sao tôi biết?
Ngoài ra, việc triển khai có thể có an toàn con trỏ nghiêm ngặt, trong trường hợp đó, giá trị con trỏ không phải là giá trị con trỏ xuất phát an toàn là giá trị con trỏ không hợp lệ trừ khi đối tượng hoàn chỉnh được tham chiếu có thời lượng lưu trữ động và đã được khai báo trước đó
Đợi đã, vậy thậm chí có khả năng tôi cần phải gọi declare_reachable()
trên mọi con trỏ? Làm sao tôi biết?
Bây giờ, bạn có thể chuyển đổi sang intptr_t
, được xác định rõ, đưa ra biểu diễn số nguyên của một con trỏ có nguồn gốc an toàn. Tất nhiên, là một số nguyên, nó hoàn toàn hợp pháp và được xác định rõ để tăng nó theo ý muốn.
Và có, bạn có thể chuyển đổi intptr_t
trở lại thành một con trỏ, cũng được xác định rõ. Chỉ là, không phải là giá trị ban đầu, nó không còn được đảm bảo rằng bạn có một con trỏ có nguồn gốc an toàn (rõ ràng). Tuy nhiên, tất cả trong tất cả, đối với thư của tiêu chuẩn, trong khi được xác định theo triển khai, đây là điều hợp pháp 100% phải làm:
[expr.reinterpret.cast] 5
Giá trị của kiểu tích phân hoặc kiểu liệt kê có thể được chuyển đổi rõ ràng thành một con trỏ. Một con trỏ được chuyển đổi thành một số nguyên có kích thước đủ [...] và trở về cùng một loại con trỏ [...] giá trị ban đầu; ánh xạ giữa con trỏ và số nguyên được xác định theo cách khác.
Cuộc đuổi bắt
Con trỏ chỉ là số nguyên thông thường, chỉ có bạn tình cờ sử dụng chúng làm con trỏ. Oh nếu chỉ có vậy là đúng!
Thật không may, tồn tại các kiến trúc trong đó hoàn toàn không đúng và chỉ tạo ra một con trỏ không hợp lệ (không phải là bỏ qua nó, chỉ cần có nó trong một thanh ghi con trỏ) sẽ gây ra một cái bẫy.
Vì vậy, đó là cơ sở của "thực hiện được xác định". Điều đó, và thực tế là việc tăng một con trỏ bất cứ khi nào bạn muốn, như bạn vui lòng dĩ nhiên có thể gây ra tràn, điều mà tiêu chuẩn không muốn đối phó. Sự kết thúc của không gian địa chỉ ứng dụng có thể không trùng với vị trí tràn và bạn thậm chí không biết liệu có bất kỳ thứ gì như tràn cho con trỏ trên một kiến trúc cụ thể không. Nói chung, đó là một mớ hỗn độn ác mộng không liên quan đến lợi ích có thể có.
Đối phó với điều kiện một đối tượng quá khứ ở phía bên kia, rất dễ dàng: Việc thực hiện phải đơn giản là đảm bảo không có đối tượng nào được phân bổ để byte cuối cùng trong không gian địa chỉ bị chiếm dụng. Vì vậy, điều đó được xác định rõ là nó hữu ích và tầm thường để đảm bảo.