2011-12-19 29 views
8

Tôi đã từng chơi với một số tính năng mới trong C++ 11 và tôi đã cố gắng viết chương trình sau đây, hy vọng nó không hoạt động. Nhiều bất ngờ của tôi, nó (trên GCC 4.6.1 trên Linux x86 với 'std = C++ 0x' cờ):C++ Lambdas, Chụp hình, Ptr thông minh và Ngăn xếp: Tại sao tính năng này hoạt động?

#include <functional> 
#include <iostream> 
#include <memory> 

std::function<int()> count_up_in_2s(const int from) { 
    std::shared_ptr<int> from_ref(new int(from)); 
    return [from_ref]() { return *from_ref += 2; }; 
} 

int main() { 
    auto iter_1 = count_up_in_2s(5); 
    auto iter_2 = count_up_in_2s(10); 

    for (size_t i = 1; i <= 10; i++) 
     std::cout << iter_1() << '\t' << iter_2() << '\n' 
     ; 
} 

tôi đã mong đợi 'from_ref' bị xóa khi mỗi thực hiện các lambda chạy lại. Đây là lý do của tôi: một khi count_up_in_2s được chạy, from_ref được bật ra khỏi ngăn xếp, bởi vì lambda trả về không cần chạy ngay lập tức, vì nó được trả về, không có tham chiếu nào khác tồn tại trong một khoảng thời gian ngắn cho đến khi tham chiếu tương tự đẩy trở lại khi lambda thực sự chạy, vì vậy không nên tính số tham chiếu shared_ptr của số không và sau đó xóa dữ liệu?

Trừ khi bắt chước lambda của C++ 11 là rất nhiều thông minh hơn là tôi cho nó tín dụng, nếu có, tôi sẽ hài lòng. Nếu đây là trường hợp, tôi có thể giả định rằng biến C++ 11 của biến sẽ cho phép tất cả các thủ thuật scoping/đóng cửa từ vựng một la Lisp miễn là/cái gì đó/là chăm sóc bộ nhớ động được phân bổ? Tôi có thể giả định rằng tất cả các tài liệu tham khảo bị bắt sẽ vẫn còn sống cho đến khi lambda chính nó bị xóa, cho phép tôi sử dụng smart_ptrs trong thời trang trên?

Nếu đúng như tôi nghĩ, điều này có nghĩa là C++ 11 cho phép lập trình bậc cao hơn không? Nếu vậy, tôi nghĩ rằng ủy ban C++ 11 đã làm một công việc tuyệt vời =)

Trả lời

7

Lambda chụp from_ref theo giá trị, do đó, nó tạo một bản sao. Do bản sao này, số ref không phải là 0 khi from_ref bị hủy, đó là 1 vì bản sao vẫn tồn tại trong lambda.

+1

Vì vậy, tôi phải hiểu rằng đối tượng std :: chức năng tự lưu trữ các giá trị chụp trong suốt thời gian của instance? Và bằng cách lưu trữ tham chiếu này, số tham chiếu shared_ptr không bao giờ chạm 0? Ah tôi thấy. Làm thế nào thanh lịch. – Louis

+3

@Louis no, không phải là đối tượng 'function', mà là lambda. 'std :: function' không biết về các ảnh chụp của lambdas. –

+0

Vì vậy, việc chụp và lưu trữ tham chiếu được xử lý như một trường hợp đặc biệt thay vì được lưu trữ như một thành viên trong thể hiện hàm std ::, nói. Cảm ơn. – Louis

4

Sau đây:

std::shared_ptr<int> from_ref(new int(from)); 
return [from_ref]() { return *from_ref += 2; }; 

chủ yếu là tương đương với điều này:

std::shared_ptr<int> from_ref(new int(from)); 
class __uniqueLambdaType1432 { 
    std::shared_ptr<int> capture1; 
public:   
    __uniqueLambdaType1432(std::shared_ptr<int> capture1) : 
    capture1(capture1) { 
    } 
    decltype(*capture1 += 2) operator()() const { 
    return *capture1 += 2; 
    } 
}; 
return __uniqueLambdaType1432(from_ref); 

nơi __uniqueLambdaType1432 là một loại chương trình toàn cầu độc đáo khác biệt với bất kỳ, các loại lambda thậm chí khác khác được tạo ra bởi một lexically giống hệt nhau biểu thức lambda. Tên thực tế của nó không có sẵn cho lập trình viên, và bên cạnh đối tượng xuất phát từ biểu thức lambda gốc, không có trường hợp nào khác của nó có thể được tạo ra bởi vì hàm tạo thực sự bị ẩn với ma thuật trình biên dịch.

1

from_ref được ghi lại theo giá trị.

lập luận của bạn hoạt động nếu bạn thay thế

return [from_ref]() { return *from_ref += 2; }; 

với

return [&from_ref]() { return *from_ref += 2; }; 
Các vấn đề liên quan