2015-11-30 13 views
8

Tất cả bây giờ và sau đó tôi đưa ra với mã như thế này:chụp tất cả mọi thứ vs chụp chỉ có một số trong một lambda

// lazy lambda: 
[&] { 
// use references to a, b, c 
} 

// pedantic lambda 
[&a, &b, &c] { 
// use references to a, b, c 
} 

Tôi muốn biết đó của lambdas là tốt hơn về hiệu suất và có lẽ kích thước thực thi theo chuẩn C++ 14 (hoặc mới hơn) và kinh nghiệm thực tế của bạn với các trình biên dịch.

+0

Nếu lambda lười biếng kết thúc việc nắm bắt các biến tương tự như lambda pedantic, tôi thấy không có lý do tại sao hiệu suất hoặc thậm chí các mã máy được tạo nên khác nhau. – alain

+2

IDK nếu nó được cho phép theo tiêu chuẩn hay không nhưng tôi nghĩ rằng trình biên dịch sẽ chỉ nắm bắt các biến mà bạn sử dụng. – NathanOliver

+3

Sự khác biệt hoàn toàn là cú pháp, không phải ngữ nghĩa. Cả hai lambdas làm điều tương tự. –

Trả lời

3

Loại trừ trường hợp tầm thường mà bạn nắm bắt một cách rõ ràng nội dung không được đề cập trong lambda, có hai trường hợp góc có thể có sự khác biệt.

Đầu tiên, các ảnh chụp ngầm ẩn thường không nắm bắt các thực thể không được sử dụng không đúng (nhưng xem mục tiếp theo cho ngoại lệ cho điều này). Điều này bao gồm, trong số những thứ khác, những điều đề cập trong toán hạng unevaluated như những decltypesizeof, cũng như một số constconstexpr biến địa phương khi được sử dụng trong những bối cảnh nhất định (tham khảo ý kiến ​​[basic.def.odr] cho các thiết lập đầy đủ các quy tắc):

void f(int){} 
void f2(const int &) {} 
void t() { 
    const int x = 8; 
    constexpr double y = 8; 
    const double z = 8; 
    auto g = []{ f(x); }; // OK 
    auto g1 = [=]{ f(x); }; // OK, does not capture x 

    // usually won't fire, though not guaranteed 
    static_assert(sizeof(g) == sizeof(g1), "!!"); 

    auto g2 = []{ f(y); }; // OK 
    auto g3 = []{ f(z); }; // Error, must capture z 

    auto g4 = []{ f2(x); }; // Error, must capture x since it's odr-used 
    auto g5 = [=]{ f2(x); }; // OK, captures x 
    auto g6 = []{ f2(+x); }; // OK, doesn't odr-use x 
    auto g7 = []{ f2(y); }; // OK 
} 

Nếu bạn viết danh sách chụp theo cách thủ công, có thể bạn sẽ nắm bắt được nhiều hơn bạn cần về mặt kỹ thuật, bởi vì các quy tắc quản lý những gì được sử dụng hoặc không được sử dụng là khá phức tạp.

Thứ hai, các ảnh chụp ngầm trong các lambdas chung sẽ chụp những thứ được sử dụng trong một biểu thức phụ thuộc, ngay cả khi chúng không nhất thiết phải được sử dụng không đúng, cho sự tỉnh táo. Vay an example from the standard:

void f(int, const int (&)[2] = {}) { } // #1 
void f(const int&, const int (&)[1]) { } // #2 
void test() { 
    const int x = 17; 
    auto g2 = [=](auto a) { 
    int selector[sizeof(a) == 1 ? 1 : 2]{}; 
    f(x, selector); // OK: is a dependent expression, so captures x 
        // Will actually odr-use x only if sizeof(a) == 1 
    }; 
} 

Tuy nhiên, bạn không thực sự cần thiết để nắm bắt cái gì đó có thể-hoặc-thể-không-thể-ODR được sử dụng khi viết một lambda chung; bạn chỉ bắt buộc phải nắm bắt nó nếu bạn khởi tạo một chuyên môn của toán tử cuộc gọi hàm mà không sử dụng điều đó. Và vì vậy nếu bạn không bao giờ gọi lambda chung kết quả theo cách mà sẽ sử dụng điều đó ở vấn đề, thì việc nắm bắt tiềm ẩn có thể chiếm nhiều hơn mức tối thiểu bạn cần. Ví dụ, điều này được phép:

void test() { 
    const int x = 17; 
    auto g3 = [](auto a) { // no capture 
    int selector[sizeof(a) == 1 ? 1 : 2]{}; 
    f(x, selector); // OK for now 
    }; 
} 

miễn là bạn đừng gọi g3 với bất cứ điều gì có kích thước là 1: g3(0) là OK trên các hệ thống điển hình; g3('\0') thì không.

5

Không có sự khác biệt trong ví dụ này. Trình biên dịch sẽ chỉ nắm bắt các biến được tham chiếu rõ ràng trong lambda, làm cho việc nắm bắt lười tương đương với một biến rõ ràng.

Chụp hình lười biếng thuận tiện hơn một chút. Thay đổi phần thân của lambda để sử dụng các biến bị bắt bổ sung, hoặc loại bỏ tất cả các tham chiếu đến một biến được capture từ một lambda hiện có, thông thường cũng sẽ yêu cầu cập nhật một danh sách chụp rõ ràng. Với một nắm bắt lười biếng trình biên dịch sẽ làm mọi thứ cho bạn.

1

Giống như những người đã nói ở trên, sẽ không có sự khác biệt về mã được tạo. Tuy nhiên, tôi tin rằng, tốt hơn là rõ ràng - nó cho khả năng đọc tốt hơn (dễ dàng hơn để giải thích về vòng đời biến đổi) và cũng cung cấp cho bạn sự hỗ trợ tốt hơn từ trình biên dịch, tạo ra lỗi khi bạn truy cập biến mà bạn không có ý định.

Tôi tin rằng 'chụp hình lười biếng' không phải là một tính năng hay.

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