2015-12-11 11 views
5
template <typename T> 
void myswap(T a,T b) 
{ 
    T temp = a; 
    a = b; 
    b = temp; 
} 
int main() 
{ 
    int m(20),n(30); 
    myswap(ref(m),ref(n)); 
    //m is still 20 and n is still 30 
} 

Tại sao giá trị của m và n không thay đổi? Chuyển một giá trị được bọc trong std::ref đến một hàm INCREMENT dẫn đến thay đổi giá trị trong biến ban đầu (biến trong khung ngăn xếp gọi hàm INCREMENT). Hoặc, việc sử dụng std::ref có bị hạn chế/giới hạn không?std :: chức năng ref và swap dường như không hoạt động tốt với nhau

Trả lời

8

std::ref (và liên quan std::reference_wrapper) là công cụ được thiết kế cho các trường hợp sử dụng rất cụ thể trong thư viện chuẩn và chỉ nên được sử dụng cho những trường hợp đó; nếu bạn muốn sử dụng nó ở những nơi của riêng bạn, bạn phải hiểu nó một cách chi tiết và tôn trọng những gì nó làm.

Về cơ bản, một reference_wrapper gần giống với con trỏ hơn tham chiếu. Vì vậy, thay thế một con trỏ trong chức năng trao đổi của bạn và bạn sẽ thấy rằng không có lý do gì để cho rằng nó sẽ thực sự trao đổi:

void myswap(int* a, int* b) 
{ 
    int* temp = a; 
    a = b; 
    b = temp; 
} 
+0

Hoặc sử dụng 'std :: swap' – 101010

+0

Câu đầu tiên hơi gây hiểu nhầm.Tất nhiên 'std :: ref' không giới hạn trong thư viện chuẩn (vì bạn cũng lưu ý nó sau nó) –

1

bạn myswap mất các yếu tố của giá trị.

Về cơ bản, bạn trao đổi hai tham chiếu (std::reference_wrapper s) tại phạm vi địa phương của hàm.

Các giá trị mà chúng chỉ đến sẽ không thay đổi.


template <typename T> void incrementer(T a) { ++a; } int a = 20; 

Trong trường hợp này có một chuyển đổi để int&with:

operator T&() const noexcept { return *_ptr; } 

Trong code của bạn, mặt khác:

T temp = a; 

chỉ đơn giản là sẽ gọi constructor sao chép, sao chép con trỏ cơ bản:

reference_wrapper(const reference_wrapper&) noexcept = default; 

sau đó, trên dòng tiếp theo bạn lại sao chép con trỏ:

reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; 
+0

@Karoly: Tôi đang chuyển một tham số_wrapper đến hàm. không phải số nguyên đơn thuần. http://stackoverflow.com/questions/26766939/difference-between-stdreference-wrapper-and-simple-pointer?lq=1 (về reference_wrapper và các lợi ích của nó). –

+0

@ 101010: Đó không phải là điều tôi đang nói sao? Hãy để tôi chỉnh sửa để làm cho nó rõ ràng. –

+0

Có, chúng lấy các phần tử (thuộc loại std :: ref) theo giá trị. Nhưng một bản sao cho m và n không được tạo trong hàm myswap. Hai tài liệu tham khảo mới vẫn trỏ đến m & n được tạo ra trong khung áp chót. –

4

Mã của bạn tạo ra hai std::reference_wrapper đối tượng tạm thời và giao dịch hoán đổi họ, vì vậy họ đề cập đến đối tượng khác nhau. Tất cả những gì xảy ra là bạn hoán đổi hai đối tượng reference_wrapper, không phải mục tiêu của chúng.

Nếu bạn tự viết những gì chức năng mẫu sẽ tạo ra lý do cho hành vi nên được rõ ràng:

void myswap(std::reference_wrapper<int> a, std::reference_wrapper<int> b) 
{ 
    std::reference_wrapper<int> temp = a; 
    a = b; 
    b = a; 
} 

Rõ ràng điều này không thay đổi int đối tượng, chỉ có reference_wrapper đối tượng.

Nếu những gì bạn đang cố gắng làm là bắt buộc myswap để tham khảo bạn cần gọi myswap<int&>(m, n), bạn không thể mô phỏng điều đó bằng cách sử dụng reference_wrapper. Nhưng bạn nên thực sự sửa chữa myswap, bởi vì nó khá vô dụng theo cách nó được viết ngay bây giờ.

+0

Thật vậy, nhưng không nên tạm thời trỏ đến m và n được tạo trong khung ngăn áp áp chót ?. Vượt qua một biến được bao bọc trong std :: ref cho một hàm increment và bạn sẽ thấy giá trị wud đã được cập nhật. Không phải là một tạm thời tạo ra trong chức năng tăng? Sau đó, thay đổi được phản ánh như thế nào trong biến ban đầu. –

+0

@Jon: Có, nó KHÔNG tính 'theo giá trị'. mẫu gia tăng khoảng trống (T a) { ++ a; } int a = 20; incrementer (ref (a)); // a là 21 bây giờ –

+0

'reference_wrapper' không hỗ trợ toán tử tăng, do đó hàm gia tăng gây ra chuyển đổi thành' int & 'và tăng mục tiêu. Hàm hoán đổi chỉ sử dụng hàm tạo bản sao và gán bản sao, mà 'reference_wrapper' _does_ hỗ trợ, do đó các hoạt động đó hoạt động trực tiếp trên' reference_wrapper', không phải trên đích. –

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