Cuối cùng tôi đã theo dõi lỗi rất lạ, được gây ra bởi destructor kép gọi. Đây là mã tối thiểu nhằm tái tạo lỗi:Cuộc gọi destructor kép lạ khi sử dụng shared_ptr
#include <iostream>
#include <memory>
#include <set>
class cEventSystem {
public:
cEventSystem() {
std::cout << "constructor: " << this << std::endl;
}
~cEventSystem() {
std::cout << "destructor: " << this << std::endl;
}
};
class cSubscriber {
public:
cSubscriber(cEventSystem& eventSystem) : eventSystem(eventSystem) {}
virtual ~cSubscriber() {}
virtual void onEvent() = 0;
protected:
cEventSystem& eventSystem;
};
class cTileBrowser: public cSubscriber {
public:
cTileBrowser(cEventSystem eventSystem) : cSubscriber(eventSystem) {}
void onEvent() {}
};
class cGui: public cSubscriber {
public:
cGui(cEventSystem& eventSystem) : cSubscriber(eventSystem) {
tileBrowser = std::make_shared<cTileBrowser>(eventSystem);
}
void onEvent() {}
std::shared_ptr<cTileBrowser> tileBrowser;
};
int main() {
cEventSystem eventSystem;
cGui gui(eventSystem);
}
Đầu ra là:
constructor: 0x7fffffffe67f
destructor: 0x7fffffffe2df
destructor: 0x7fffffffe67f
Như bạn có thể thấy các destructor đầu tiên là không cần thiết và nó được gọi trên đối tượng khác nhau mà đã không được xây dựng tại tất cả (địa chỉ là khác nhau), nhưng trong mã thực sự của tôi địa chỉ là đủ gần và nó làm hỏng các container tôi có trong hệ thống sự kiện.
Gỡ lỗi cho thấy rằng đó là make_shared gây ra cuộc gọi destructor đó.
Điều gì gây ra cuộc gọi hủy không mong muốn đó và làm thế nào tôi có thể loại bỏ nó? Tôi sử dụng g ++ 4.7 với cờ C++ 11.
Vấn đề là cuộc gọi hủy không mong muốn thường là (90% số lần) làm hỏng vùng chứa hệ thống sự kiện trong mã thực sự của tôi gây ra segfaults, nhưng hiếm khi nó không làm hỏng nó và mọi thứ hoạt động.
người đàn ông, bạn là người hùng, nó hoạt động trong mã thực của tôi ngay bây giờ! Nhưng tại sao bản sao tạm thời lại không an toàn đến nỗi nó có thể làm hỏng dữ liệu của tôi trong bộ nhớ? Tôi hầu như luôn luôn đi qua tham chiếu (điều này là một sai lầm), nhưng có vẻ như ít nhất là lạ với tôi. – user1873947
@ user1873947, vì hàm tạo bản sao là trình biên dịch được tạo nên có thể là do điều sai. Nếu nó làm cho một bản sao của một con trỏ ví dụ và destructor sau đó xóa nó, bạn còn lại với một con trỏ lơ lửng trong đối tượng ban đầu. –
@Mark Ransom đó là nó. Trong mã thực sự của tôi, tôi có một tập hợp các con trỏ. – user1873947