2011-02-06 10 views
7

this other question asking about how comparing pointers is supposed to be interpreted wrt C++ Std.Con trỏ có được phép làm khóa trong các thùng chứa STL đã đặt hàng không?

Vì vậy, tôi đã tự hỏi những gì C++ Std có nói về việc sử dụng con trỏ như phím trong thư viện chuẩn lệnh (STL) container - tức là một phép có

std::map<T1*, T2>

và nay do đặc điểm kỹ thuật của std::less hoặc builtin operator <?

+0

btw, bạn có muốn sử dụng các địa chỉ làm khóa hoặc giá trị của những thứ mà chúng trỏ đến là khóa không? Trong trường hợp thứ hai, bạn sẽ phải cung cấp bộ so sánh tùy chỉnh – sellibitze

+0

liên quan: [kiểm tra nếu con trỏ chỉ trong một mảng] (http://stackoverflow.com/questions/4657976/) – fredoverflow

Trả lời

11

Có, bởi vì nó sử dụng std::less, bắt buộc phải dẫn đến tổng số đơn đặt hàng ngay cả khi < thì không. (< sẽ được phép xử lý các con trỏ khác nhau từ các trình tự khác nhau như nhau, điều này sẽ dẫn đến hành vi kỳ lạ là map v.v. nếu bạn chèn con trỏ từ các trình tự khác nhau).

+1

Để cụm từ này hơi khác nhau: Để báo giá sellibitze từ một bình luận cho một câu trả lời dưới đây: "... nó an toàn để sử dụng con trỏ như các phím trong thùng chứa kết hợp. Nhưng điều này không có gì để làm với các nhà điều hành ít hơn vì std :: ít là bộ so sánh mặc định cho các vùng chứa này và C++ tạo ra các bảo đảm đặc biệt cho std :: less trong trường hợp T là một kiểu con trỏ. ... " –

-3

Có. Con trỏ có thể so sánh thông qua toán tử <().

Nếu con trỏ không trỏ đến các phần tử của cùng một mảng hoặc phần tử trong cùng một đối tượng, tiêu chuẩn C++ cho biết hành vi không được chỉ định [expr.rel].

Tiêu chuẩn cho biết hành vi không xác định có nghĩa là hành vi được xác định [defns.unspecified].

Nếu trình biên dịch của bạn bảo đảm thứ tự yếu của con trỏ, bạn có thể sử dụng bất kỳ con trỏ nào có vùng chứa liên kết.

Hầu hết các trình biên dịch đều so sánh con trỏ bằng cách so sánh các địa chỉ bộ nhớ. Trên hầu hết các kiến ​​trúc, sự so sánh này tạo thành một trật tự yếu nghiêm ngặt.

Do đó, an toàn để sử dụng con trỏ làm khóa.

+0

chỉ khi chúng trỏ đến các phần tử của cùng một mảng. Tiêu chuẩn C++ đảm bảo mạnh mẽ hơn cho std :: less là giá trị mặc định cho các thùng chứa liên kết có thứ tự – sellibitze

+0

@sellibitze: Con trỏ không liên quan đến mảng. Các con trỏ tới các phần tử của các mảng khác nhau là ít so sánh. – joke

+1

@joke: Không, tiêu chuẩn không cho phép so sánh các con trỏ tùy ý với '<'. – fredoverflow

0

"Chúng có thể hợp lệ nhưng không" là câu trả lời tôi đưa ra.

Rõ ràng có vấn đề về khả năng so sánh mà bạn nâng cao, nhưng lý do bạn không muốn là do thiếu quản lý tham chiếu về con trỏ "vanilla". Việc xóa đối tượng này rất dễ dàng mà không bị xóa khỏi vùng chứa, dẫn đến con trỏ không hợp lệ và vi phạm quyền truy cập vào lần tiếp theo bạn truy cập vào nó.

+0

Đó không nhất thiết phải hợp lệ - những thứ như unique_ptr hoặc shared_ptr cũng có thể cung cấp các toán tử so sánh dựa trên con trỏ nằm bên dưới. – Puppy

3

Tôi muốn thêm một lý do khác để không thực hiện việc này. Nếu bạn đang sử dụng con trỏ theo cách này, và nếu bạn có một lỗi phụ thuộc vào thứ tự của các phần tử của một thùng chứa, thì nó sẽ rất khó tìm. Ngay cả khi chương trình của bạn có vẻ là hoàn toàn xác định, nó sẽ không được. Thứ tự của các phần tử trong một thùng chứa phụ thuộc vào thuật toán mà bộ cấp phát bộ nhớ sử dụng, điều này hoàn toàn nằm ngoài tầm kiểm soát của bạn. Nếu bạn chạy cùng một ví dụ muliple lần mà không cần khởi động lại chương trình của bạn, một số có thể thất bại và những người khác thành công.

Đây là tiếng nói của trải nghiệm cay đắng. Tôi đã làm điều này với một dự án trình gỡ lỗi một lần, nơi tôi có các thùng chứa đầy các ký hiệu C++. Khi tôi cần sắp xếp các ký hiệu, tôi đã kết thúc với các biểu tượng khác nhau, nhưng có cùng tên (nghĩ rằng các hàm bị quá tải) và chúng giống nhau về mọi mặt khác. Vì vậy, trong trường hợp này tôi so sánh chúng như một phương sách cuối cùng bằng địa chỉ của đối tượng ký hiệu. Tôi chạy vào một số lỗi mà rõ ràng là không xác định, trong đó không xác định được gây ra bởi hiện tượng này. Đôi khi phải mất hơn 10 hoặc 15 lần để tái tạo các vấn đề. Cuối cùng tôi đã dành thời gian để loại bỏ phân loại theo địa chỉ, và điều đó đã cứu tôi rất nhiều rắc rối trong thời gian dài hơn.

Với điều đó đã nói, tôi sẽ không nói rằng tôi chưa thực hiện việc này gần đây. Nhưng mỗi khi tôi làm điều đó tôi cảm thấy như đó là một sai lầm.