Các mã sau đây trông khá vô hại từ cái nhìn đầu tiên. Một người dùng sử dụng chức năng bar()
để tương tác với một số chức năng thư viện. (Điều này thậm chí có thể đã hoạt động trong một thời gian dài kể từ khi bar()
trả về một tham chiếu đến một giá trị không tạm thời hoặc tương tự.) Tuy nhiên, bây giờ nó chỉ đơn giản là trả về một thể hiện mới của B
. B
một lần nữa có một hàm a()
trả về một tham chiếu đến một đối tượng của kiểu lặp A
. Người dùng muốn truy vấn đối tượng này dẫn đến một segfault vì B
đối tượng tạm thời được trả về bar()
bị hủy trước khi lặp lại bắt đầu.
Tôi thiếu quyết đoán ai (thư viện hoặc người dùng) sẽ đổ lỗi cho việc này. Tất cả các thư viện cung cấp các lớp trông có vẻ sạch sẽ đối với tôi và chắc chắn không làm gì khác (trả lại các tham chiếu cho các thành viên, trả về các thể hiện ngăn xếp, ...) so với rất nhiều mã khác hiện có. Người dùng dường như cũng không làm gì sai cả, anh ta chỉ lặp đi lặp lại trên một số đối tượng mà không làm bất cứ điều gì liên quan đến các đối tượng đó suốt đời.
(Một câu hỏi liên quan có thể là: Người ta có nên thiết lập quy tắc chung rằng mã không nên "dựa trên phạm vi để lặp lại" đối với một thứ được lấy bởi nhiều hơn một cuộc gọi bị xiềng xích trong tiêu đề vòng lặp vì bất kỳ cuộc gọi nào trong số này có thể trả về giá trị?)
#include <algorithm>
#include <iostream>
// "Library code"
struct A
{
A():
v{0,1,2}
{
std::cout << "A()" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
int * begin()
{
return &v[0];
}
int * end()
{
return &v[3];
}
int v[3];
};
struct B
{
A m_a;
A & a()
{
return m_a;
}
};
B bar()
{
return B();
}
// User code
int main()
{
for( auto i : bar().a() )
{
std::cout << i << std::endl;
}
}