C++ 11 lambdas là tuyệt vời!Trong cú pháp lambda C++ 11, đóng cửa phân bổ đống?
Nhưng có một điều bị thiếu, đó là cách xử lý dữ liệu có thể thay đổi một cách an toàn.
Sau đây sẽ cho đếm xấu sau khi đếm đầu tiên:
#include <cstdio>
#include <functional>
#include <memory>
std::function<int(void)> f1()
{
int k = 121;
return std::function<int(void)>([&]{return k++;});
}
int main()
{
int j = 50;
auto g = f1();
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
}
cho,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
121
8365280
8365280
8365280
Lý do là sau khi f1()
lợi nhuận, k
là ra khỏi phạm vi nhưng vẫn trên stack. Vì vậy, lần đầu tiên g()
được thực hiện k
là tốt, nhưng sau đó ngăn xếp bị hỏng và k
mất giá trị của nó.
Vì vậy, cách duy nhất tôi đã quản lý để thực hiện việc đóng cửa một cách an toàn được trả lại trong C++ 11 là để phân bổ biến khép kín một cách rõ ràng trên heap:
std::function<int(void)> f2()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
return std::function<int(void)>([=]{return (*o)++;});
}
int main()
{
int j = 50;
auto g = f2();
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
}
Ở đây, [=]
được sử dụng để đảm bảo con trỏ chia sẻ được sao chép, không được tham chiếu, do đó việc xử lý bộ nhớ được thực hiện chính xác: bản sao được phân bổ heap của k
phải được giải phóng khi hàm được tạo g
nằm ngoài phạm vi. Kết quả là như mong muốn,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
121
122
123
124
Nó khá xấu xí để đề cập đến các biến bởi dereferencing họ, nhưng chúng ta có thể sử dụng tài liệu tham khảo thay vì:
std::function<int(void)> f3()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
int &p = *o;
return std::function<int(void)>([&]{return p++;});
}
Trên thực tế, điều này kỳ quặc mang lại cho tôi,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
0
1
2
3
Bất kỳ ý tưởng nào tại sao? Có lẽ nó không lịch sự để có một tham chiếu của một con trỏ chia sẻ, bây giờ mà tôi nghĩ về nó, vì nó không phải là một tài liệu tham khảo theo dõi. Tôi thấy rằng việc di chuyển tài liệu tham khảo để bên trong lambda gây ra một vụ tai nạn,
std::function<int(void)> f4()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
return std::function<int(void)>([&]{int &p = *o; return p++;});
}
hiến,
g++-4.5 -std=c++0x -o test test.cpp && ./test
156565552
/bin/bash: line 1: 25219 Segmentation fault ./test
Trong mọi trường hợp, nó sẽ được tốt đẹp nếu có một cách để tự động thực hiện việc đóng cửa một cách an toàn được trả lại qua phân bổ đống. Ví dụ: nếu có một giải pháp thay thế cho [=]
và [&]
cho biết rằng các biến phải được phân bổ theo heap và được tham chiếu qua tham chiếu đến các con trỏ được chia sẻ. Suy nghĩ ban đầu của tôi khi tôi biết về std::function
là nó tạo ra một đối tượng đóng gói đóng cửa, do đó nó có thể cung cấp dung lượng cho môi trường đóng cửa, nhưng các thử nghiệm của tôi cho thấy điều này dường như không giúp ích gì.
Tôi nghĩ rằng đóng cửa có thể trả lại an toàn trong C++ 11 sẽ là tối quan trọng khi sử dụng chúng, có ai biết cách này có thể được thực hiện thanh lịch hơn không?
Bạn nên chạy thử nghiệm như thế này bên trong Valgrind, bởi vì bạn đang nhìn thấy hành vi đúng cơ hội khi truy cập bộ nhớ deallocated. – Potatoswatter
static int k = 121; – adnako