Hôm nay chúng tôi đã tìm ra nguyên nhân của một lỗi khó chịu chỉ xảy ra không liên tục trên một số nền tảng nhất định. Đun sôi xuống, mã của chúng tôi trông như thế này:
class Foo {
map<string,string> m;
void A(const string& key) {
m.erase(key);
cout << "Erased: " << key; // oops
}
void B() {
while (!m.empty()) {
auto toDelete = m.begin();
A(toDelete->first);
}
}
}
Vấn đề có vẻ rõ ràng trong trường hợp đơn giản này: B
chuyển tham chiếu đến khóa tới A
, loại bỏ mục nhập bản đồ trước khi thử in nó. (Trong trường hợp của chúng tôi, nó không được in, nhưng được sử dụng theo cách phức tạp hơn) Đây tất nhiên là hành vi không xác định, vì key
là một tham chiếu lơ lửng sau khi gọi đến erase
.
Sửa lỗi này là chuyện nhỏ - chúng tôi chỉ thay đổi loại tham số từ const string&
thành string
. Câu hỏi là: làm thế nào chúng ta có thể tránh được lỗi này ngay từ đầu? Có vẻ như cả hai chức năng đã làm đúng:
A
không có cách nào để biết điều đókey
đề cập đến thứ mà nó sắp phá hủy.B
có thể đã tạo một bản sao trước khi chuyển nó tớiA
, nhưng đó không phải là công việc của callee để quyết định lấy tham số theo giá trị hay bằng tham chiếu?
Có một số quy tắc chúng tôi không tuân theo?