2017-09-20 14 views
9
#include <iostream> 
#include <algorithm> 
#include <vector> 

int main() 
{ 
    // Block 1 
    { 
    auto inc = []() { int i = 0; return [&]() { return i++; }; }(); 
    std::vector<int> v(10, 10); 
    std::generate(v.begin(), v.end(), inc); 
    for (auto i : v) std::cout << i << std::endl; 
    } 

    // Block 2 
    { 
    auto inc = []() { int i = 0; return [&]() { return i++; }; }; 
    std::vector<int> v(10, 10); 
    std::generate(v.begin(), v.end(), inc()); 
    for (auto i : v) std::cout << i << std::endl; 
    } 
} 

Tôi không chắc chắn lý do tại sao hai khối này tạo ra các kết quả khác nhau.c + + đóng cửa với lambda

Block 1: 32767 ... 32776 
Block 2: 0 ... 10 

Và đối với std::generate máy phát điện (inc) được truyền theo giá trị, vì vậy tôi tin rằng nó nên được tốt, phải không?

Tôi đang chạy OS X.

Cảm ơn,


Lưu ý rằng các kết quả từ mã ở trên là không xác định, xem dưới đây.

+0

Không thể tạo lại, gcc v5.1.0 tạo ra cùng một đầu ra trong cả hai trường hợp – Slava

+0

Tôi đang biên dịch với phiên bản tiếng kêu 3.6.2. – Ling

+1

Nevermind, đó là UB, do đó, đầu ra cụ thể là không thích hợp – Slava

Trả lời

10

Tôi không chắc chắn lý do tại sao hai khối này tạo ra các kết quả khác nhau.

Cả hai đều là hành vi không xác định, do đó, câu hỏi là tranh luận. Trong cả hai trường hợp, chúng tôi có một lambda như:

auto f = []() { int i = 0; return [&]() { return i++; }; }; 

f() lợi nhuận một lambda rằng có một tham chiếu lủng lẳng: i bị phá hủy vào cuối cuộc gọi đến f. Nó không quan trọng khi mà tham chiếu lơ lửng xảy ra - cho dù điều đó xảy ra lâu trước khi gọi generate() hoặc vào cuộc gọi generate().

Nếu bạn muốn thực hiện một truy cập tạo ra với một lambda, cách trực tiếp là làm cho lambda có thể thay đổi và sử dụng init-chụp:

auto inc = [i=0]() mutable { return i++; }; 

Các mutable là cần thiết vì lambdas là const theo mặc định, và chúng ta cần sửa đổi trực tiếp thành viên i.


Ở trên là C++ 14 (do bắt đầu tổng quát). Chúng ta có thể làm công việc này trong C++ 11 bằng cách đơn giản thay đổi cấu trúc lồng nhau-lambda từ chụp lambda bên trong bằng cách tham khảo để chụp theo giá trị:

auto inc = []{ int i = 0; return [=]() mutable { return i++; }; }(); 
//        ~~~ ~~~~~~~ 

... Đó là loại đáng ghét, nhưng nó hoạt động?

+0

[i = 0] có yêu cầu C++ 14 không? – Slava

+0

@Slava Có, đã thêm một cách để sửa chữa ví dụ lồng nhau-lambda gốc của OP để vẫn hoạt động trong C++ 11. – Barry

+0

Cảm ơn, vì 'i' là một đối tượng tạm thời cục bộ bên trong' operator() 'nếu bạn nghĩ lambda giống như' struct'. Vì vậy, hàm lambda thu được là một tham chiếu không hợp lệ đối với biến cục bộ. Đó là lý do tại sao cả hai trường hợp đều là UB. Lúc đầu, tôi nghĩ rằng nó sẽ hoạt động giống như bao đóng thực sự. – Ling