2013-05-09 41 views
7

Trong C++, nếu bạn có một vòng lặp for mà "bản sao" đối tượng của một người dùng loại được xác định bằng cách sử dụng constructor di chuyển, nó thực hiện bất kỳ sự khác biệt nếu bạn sử dụng ++i hoặc i++ làm bộ đếm vòng lặp?Move constructor và pre-increment vs hậu increment

Tôi biết câu hỏi này có vẻ khá mơ hồ, nhưng tôi (tôi tin) đã hỏi điều này trong một cuộc phỏng vấn qua điện thoại. Tôi đã không chắc chắn nếu tôi hiểu câu hỏi một cách chính xác, và người phỏng vấn đã này như tôi không biết câu trả lời, và cắt ngắn cuộc phỏng vấn.

Anh ấy có thể nhận được gì?

+0

Xem thêm [Giải pháp GotW # 2 của Herb Sutter]: http://herbsutter.com/2013/05/13/gotw-2-solution-temporary-objects/). – jww

Trả lời

10

Trong C++, nếu bạn có một vòng lặp for rằng "bản sao" đối tượng của một người dùng loại được xác định sử dụng một constructor chuyển [...]

Trước hết, một constructor di chuyển được sử dụng cho di chuyển-xây dựng, thường có nghĩa là bạn không "sao chép": bạn có thể nhận ra di chuyển là sao chép - trên thực tế, một lớp có khả năng sao chép cũng có thể chuyển động - nhưng sau đó tại sao xác định hàm tạo di chuyển một cách rõ ràng?

[...] có tạo sự khác biệt nào nếu bạn sử dụng ++ i hoặc i ++ làm bộ đếm vòng lặp không?

Phụ thuộc vào số i là. Nếu nó là một đối tượng vô hướng, như là int, thì không có sự khác biệt nào cả.

Nếu i là một đẳng cấp loại iterator, mặt khác, ++i nên hiệu quả hơn (trên mặt đất thuần túy lý thuyết), bởi vì việc thực hiện operator ++ sẽ không cần phải tạo một bản sao của iterator để được trả lại trước khi bản thân trình vòng lặp được tăng lên.

Ở đây, ví dụ, là cách stdlibC++ định nghĩa các nhà khai thác tăng cho các loại iterator của một std::list:

_Self& 
operator++() 
{ 
    _M_node = _M_node->_M_next; 
    return *this; 
} 

_Self 
operator++(int) 
{ 
    _Self __tmp = *this; 
    _M_node = _M_node->_M_next; 
    return __tmp; 
} 

Như bạn có thể thấy, phiên bản postfix (một sự chấp nhận một giả int) có làm việc nhiều hơn cần làm: nó cần tạo một bản sao của trình lặp ban đầu để được phục hồi, sau đó thay đổi con trỏ bên trong của trình lặp, sau đó trả về bản sao.

Mặt khác, phiên bản tiền tố chỉ cần thay đổi con trỏ bên trong và trả về (tham chiếu đến) chính nó.

Tuy nhiên, xin lưu ý rằng khi hiệu suất là có liên quan, tất cả các giả định phải được sao lưu bằng cách đo lường. Trong trường hợp này, tôi không mong đợi bất kỳ sự khác biệt hợp lý giữa hai chức năng này.

+1

Nhận nó trên phần "sao chép". Tôi biết tôi không nên sử dụng từ đó. Vì vậy, điều này không có gì để làm với di chuyển xây dựng cho mỗi gia nhập, phải không? Nó phải làm gì với ints vs iterators? – Scott

+0

@Scott: Thật vậy, đó là trường hợp. Tôi sẽ mở rộng câu trả lời với một ví dụ –

+0

Andy nếu rhs là lvalue sau đó di chuyển sẽ nguy hiểm phải không? –