2012-02-08 30 views
22

Tôi biết std::queue::pop() trả về void. Vì hai lý do: an toànCó thể xếp hàng :: pop trả lại giá trị ngay bây giờ?

  1. ngoại lệ: một cái gì đó có thể ném sau khi gỡ bỏ phần tử
  2. để có thể return the value by reference

Fine.

Bây giờ, nếu tôi hiểu chính xác C++ 11 di chuyển ngữ nghĩa, thứ hai không còn là đối số hợp lệ nữa.

Vì vậy, ... điều duy nhất ngăn chặn std::queue để có hàm pop giống như trả về giá trị nằm trong khả năng mà hàm tạo di chuyển ném?

Tôi có một thời gian khó suy nghĩ về các tình huống mà một nhà xây dựng di chuyển như vậy sẽ ném. Ai biết được một ví dụ?

Tôi đoán cùng đi cho std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() và những gì không.

+0

Đó thực sự là hai câu hỏi. Một ví dụ cho một hàm khởi tạo và một 'pop' trở lại. – pmr

+0

Tôi cần một ví dụ về một nhà xây dựng di chuyển ném để hiểu tại sao chúng ta không thể có 'pop' trở lại. –

+3

Điều gì về các loại mà không có một nhà xây dựng di chuyển ở tất cả? – jalf

Trả lời

5

Sử dụng kỹ thuật SFINAE thông minh thực sự có thể có pop_and_move (nguyên tử) không thực hiện ném cho các kiểu dữ liệu không thực hiện ném hoặc không ném.

Thậm chí còn có một cấu trúc noexcept() có sẵn để xem có điều gì đó có thể bị ném hay không.

Một trong những khái niệm mới trong C++ 11 đặc biệt là mở rộng SFINAE là nếu cơ thể không biên dịch thì hàm đó không tồn tại. Vì vậy, người ta có thể thực hiện dựa trên noexcept().

Tôi sẽ nói về tính tương thích ngược, chức năng sẽ cần một tên mới, do đó cho phép nó tồn tại cùng với chức năng hiện có gọi chúng một cách riêng biệt, không phá vỡ các loại chứa không có ngữ nghĩa cho phép.

+0

Bạn có thể xây dựng trên phần mở rộng của SFINAE trong C++ 11 (một tài liệu tham khảo tiêu chuẩn sẽ được tốt đẹp)? Tôi chưa từng nghe về điều đó và muốn đọc thêm. – Grizzly

+1

Nó đã được đề cập bởi Alexandrescu trong cuộc nói chuyện của ông về các mẫu variadic trong hội nghị Going Native. Là một phần của nguyên tắc "sai số thay thế không phải là lỗi", nếu cơ thể không biên dịch thì đây cũng được coi là một sự thất bại thay thế (do đó bỏ qua sự chuyên môn hóa này). Với noexcept() có thể đã tạo một hàm có thể sử dụng di chuyển nếu có sẵn và không ném, sau đó sẽ sử dụng sao chép làm lựa chọn thứ hai nếu có sẵn và không ném và không biên dịch ngược lại. – CashCow

+1

Âm thanh đầy hứa hẹn! Câu trả lời này không phải là câu trả lời trực tiếp nhất cho câu hỏi của tôi, nhưng nó thực sự là những gì tôi đang tìm kiếm mà không biết. –

6

Không có nhiều trường hợp trong đó std::move() có thể ném vào thư viện chuẩn nhưng có trường hợp. Ví dụ, nếu container sử dụng một cấp phát stateful, con của nó cũng sử dụng phân bổ này, nhưng nó sẽ không được di chuyển đến một kết quả: điều này sẽ nhận được một phiên bản được xây dựng mặc định của một cấp phát (nếu tôi loại bỏ một cách chính xác). Cho rằng các cấp phát có trạng thái này có nghĩa là đối tượng không thể di chuyển và do đó việc xây dựng di chuyển không thành công với một ngoại lệ. Tại sao loại này sau đó có một nhà xây dựng di chuyển? Vâng, bởi vì nó có thể được instantiated với phân bổ không stateful trong trường hợp di chuyển sẽ không ném. Ngoài ra, một khi chúng ta chuyển sang các lớp do người dùng định nghĩa, chúng ta không có ý tưởng nào theo đó tình trạng di chuyển chúng có thể ném đi.

+0

Bạn sẽ đưa ra rất nhiều câu hỏi thú vị. Một ngày nào đó khi tôi có thời gian tôi sẽ đi qua hồ sơ của bạn và đọc tất cả các câu trả lời của bạn cho tất cả mọi thứ. – odinthenerd

1

Một vấn đề khác là, không phải mọi lớp học đều thực sự có lợi khi di chuyển, tức là, họ chỉ có thể có một bản sao ctor.

struct DontLikeMoves{ 
    // some data, whatever... 
    DontLikeMoves(DontLikeMoves const& other){ 
    // might throw, who knows! 
    // and this will even get called for rvalues 
    } 
}; 
Các vấn đề liên quan