2013-06-05 27 views
19

Gần đây, tôi đã "chơi" với các giá trị để hiểu hành vi của họ. Hầu hết các kết quả không surprize tôi, nhưng sau đó tôi thấy rằng nếu tôi ném một biến địa phương, các nhà xây dựng di chuyển được gọi. Cho đến lúc đó, tôi nghĩ rằng mục đích của các quy tắc ngữ nghĩa di chuyển là đảm bảo rằng đối tượng sẽ di chuyển (và trở thành không hợp lệ) chỉ khi trình biên dịch có thể phát hiện ra nó sẽ không được sử dụng nữa (như trong các đối tượng tạm thời), hoặc người dùng hứa sẽ không sử dụng nó (như trong std :: move).Tại sao việc ném biến cục bộ lại di chuyển hàm tạo?

Tuy nhiên, trong đoạn mã sau, không có điều kiện nào được giữ và biến của tôi vẫn đang được di chuyển (ít nhất là trên g ++ 4.7.3).

Tại sao lại như vậy? tiêu chuẩn

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string s="blabla"; 
    try { 
     throw s; 
    } 
    catch(...) { 
     cout<<"Exception!\n"; 
    } 
    cout<<s; //prints nothing 
} 
+3

nếu có, trông giống như lỗi trong gcc. –

+0

@kbok: Bạn nói đúng, tôi đã xóa câu trả lời của mình (vì vậy tôi trả lời nhận xét của bạn ở đây).Tôi bằng cách nào đó nghĩ rằng 's' được tuyên bố trong khối' try', nên đã đọc kỹ câu hỏi một cách cẩn thận hơn. Xin lỗi tất cả –

+0

Vui lòng báo cáo cho http://gcc.gnu.org/bugzilla - cảm ơn! –

Trả lời

5

Trong trường hợp cụ thể, đó có thể là lỗi trình biên dịch, vì biến được ném (và di chuyển từ) được tham chiếu sau đó.

Trong trường hợp chung, hãy gọi di chuyển trên throw là khái niệm giống như di chuyển trên return. Nó là tốt để gọi di chuyển tự động khi nó được biết rằng các biến không thể được tham chiếu sau khi các điểm nhất định (throw hoặc return).

+0

Cảm ơn. Nó luôn luôn là tốt để biết rằng trực giác của tôi là tốt hơn so với gcc ... – asaelr

7

C++ nói (15.1.3):

Ném một ngoại lệ copy-khởi (8,5, 12,8) một đối tượng tạm thời, được gọi là đối tượng ngoại lệ. Tạm thời là một lvalue và được sử dụng để khởi tạo biến có tên trong trình xử lý phù hợp (15.3).

đoạn này có thể cũng liên quan ở đây (12.8.31):

Khi tiêu chí nhất định được đáp ứng, một thực hiện được phép bỏ qua việc xây dựng sao chép/di chuyển của một đối tượng lớp, ngay cả khi các nhà xây dựng được lựa chọn cho hoạt động sao chép/di chuyển và/hoặc trình phá hủy đối tượng có các tác dụng phụ. Trong các trường hợp như vậy, việc triển khai xử lý nguồn và đích của thao tác sao chép/di chuyển bị bỏ qua chỉ đơn giản là hai cách khác nhau tham chiếu đến cùng một đối tượng và việc hủy bỏ đối tượng đó xảy ra vào cuối thời gian khi hai đối tượng sẽ có bị phá hủy mà không cần tối ưu hóa. sự bỏ bớt này hoạt động sao chép/di chuyển, được gọi là bản sao sự bỏ bớt, được phép trong các trường hợp sau đây (có thể được kết hợp để loại bỏ nhiều bản sao):

(...)

- trong một ném-biểu , khi toán hạng là tên của đối tượng tự động không bay hơi (không phải là tham số hàm hoặc tham số mệnh đề) , phạm vi của nó không mở rộng ra ngoài phần cuối của khối try-in kín (nếu có), thao tác sao chép/di chuyển từ toán hạng sang đối tượng ngoại lệ (15.1) có thể được bỏ qua bằng cách xây dựng đối tượng tự động trực tiếp vào đối tượng ngoại lệ

Đã đăng ký trong Visual Studio 2012, có hiệu lực:

Exception! 
blabla 

Dường như một lỗi trong GCC thực sự.

+0

Nếu vậy, trình biên dịch không được phép gọi hàm khởi tạo ngay cả khi 'ném' không nằm trong khối' try'? – asaelr

+0

@asaelr: Từ trích dẫn cập nhật có vẻ như đối tượng được ném có thể được sao chép, di chuyển hoặc thậm chí được xây dựng tại chỗ - giống như đối với giá trị trả về. –

+0

@asaelr Đúng vậy. Nhưng trong trường hợp cụ thể này, nó gọi hàm di chuyển-ctor không chính xác, vì biến này sau đó được sử dụng trong khối try-block. – Spook

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