Có gì sai khi liên kết tĩnh STL vào nhiều thư viện dùng chung?


8

Đây là kịch bản:

  1. libA.so và libB.so đều liên kết tĩnh với cùng một STL.
  2. libA.so có API công khai trả về chuỗi std ::.
  3. libB.so gọi hàm này và nhận một bản sao của chuỗi.
  4. Khi bản sao của chuỗi libB.so đi ra khỏi phạm vi, hàm hủy của chuỗi được gọi.
  5. Các lỗi seg ứng dụng đang cố gắng giải phóng chuỗi đã sao chép.

Tôi đã đọc ở nơi khác rằng liên kết tĩnh như thế này là xấu nhưng tôi muốn hiểu rõ hơn tại sao nó xấu. Bất cứ ai có thể giải thích tại sao trình tự trên sẽ sụp đổ?


1
Tại sao các trình tự trên sụp đổ?
Doc Brown

Câu trả lời:


8

Hãy suy nghĩ về điều này rất cẩn thận. libA.so được liên kết tĩnh với STL. Tuy nhiên, STL không tồn tại trong sự cô lập, nó yêu cầu thời gian chạy C (CRT). Cả hai đều cư trú trong libstdc ++. Một thư viện tĩnh. Điều này có nghĩa là libA.so và libB.so có cấu trúc dữ liệu CRT riêng biệt. Cụ thể, heap được libA.so sử dụng khác với heap được libB.so sử dụng. Phân bổ một chuỗi từ đống thời gian chạy của libA và cố gắng thoát khỏi thời gian chạy của libB sẽ không hoạt động vì thời gian chạy của libB không có bản ghi phân bổ chuỗi. Cách duy nhất để hủy chính xác chuỗi là bằng cách gọi hàm hủy trong libA.so.

Người ta có thể hỏi: nhưng libB.so nhận được một bản sao của chuỗi, phải không? Đúng, nhưng ai đã phân bổ bản sao này? Nó đã được phân bổ bằng cách sử dụng hàm tạo sao chép trong bối cảnh thời gian chạy của libA.

Điều đó nói rằng, bạn vẫn có thể sử dụng chuỗi từ libB.so. Bạn không thể phá hủy nó từ đó.

Bạn cũng có thể để libB nhận một con trỏ tới chuỗi và sau đó tạo một bản sao của nó trong bối cảnh thời gian chạy của libB. Bản sao đó có thể bị phá hủy bởi libB.

Và đó là lý do tại sao liên kết tĩnh đôi khi là xấu.


1
Tôi không rõ những gì mà chuỗi String đề cập đến ở đây. Nếu cuộc nói chuyện là của một std::stringvấn đề thì đơn giản là không tồn tại: hoặc libB.sonhận được một bản sao của chuỗi, với bộ nhớ được quản lý trong bộ nhớ của chính nó hoặc nó sẽ nhận được một tham chiếu / con trỏ tới chuỗi trong libA.sovà không cố gắng xóa chuỗi từ bộ nhớ riêng của nó.
Konrad Rudolph

1
@KonradRudolph Trong số những người khác, (N) tối ưu hóa RVO tạo ra các tình huống trong đó chuỗi trả về được xây dựng bởi libA.so trong khi bị phá hủy bởi libB.so.
Sjoerd

Câu trả lời này phù hợp với những gì tôi đã thấy trong thực tế nên tôi đoán phần tôi không hiểu đầy đủ là cách heap hoạt động cho mỗi thư viện. Ban đầu tôi nghĩ rằng heap là một thứ toàn cầu duy nhất trong quy trình nhưng cách bạn mô tả nó làm cho nó có vẻ như có nhiều đống. Đây có phải chỉ là vấn đề làm thế nào các cấp phát (trong libc?) Được thực hiện hay có cái gì khác kiểm soát điều này (như trình nạp) không?
user1509041

Việc có một đống toàn cầu hay nhiều đống trong một quy trình tùy thuộc vào việc triển khai CRT cụ thể đang được sử dụng. Tôi đã thấy cả hai trường hợp. Bạn dường như có nhiều đống. Trình tải không có gì để làm với đống.
Hadi Brais

1
@AymanSalah Vâng, nó sẽ hoạt động tốt. Phiên bản HĐH chỉ quan trọng khi bạn sử dụng API dành riêng cho hệ điều hành thay vì API tiêu chuẩn ngôn ngữ.
Hadi Brais

3

STL được gọi là "trạng thái đầy đủ" (ngược lại với "trạng thái không") có nghĩa là nó có một số nội dung tĩnh bên trong. Khi bạn liên kết STL tĩnh với cả libA.so và libB.so, bạn sẽ nhận được hai bản sao của thư viện STL trong bộ nhớ trong thời gian chạy (với hai bản sao của nội dung tĩnh). Mỗi bản sao trong số hai bản sao đó quản lý tài nguyên được phân bổ một cách độc lập và tài nguyên được phân bổ trong một phiên bản của thư viện không thể được giải phóng trong một bản sao khác

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.