2009-11-05 34 views
9

Tôi đang phát triển một thư viện dùng C++ trong Linux, và tôi muốn thư viện này sử dụng log4cxx cho mục đích ghi nhật ký. Tuy nhiên, tôi không chắc chắn làm thế nào để thiết lập này. Để log4cxx hoạt động, tôi cần phải tạo một đối tượng logger. Làm cách nào để đảm bảo đối tượng này được tạo khi thư viện của tôi được tải?Cách khởi tạo thư viện dùng chung trên Linux

Tôi nghi ngờ rằng sẽ dễ dàng nhất để tạo đối tượng logger dưới dạng biến toàn cục và sau đó sử dụng nó từ bất kỳ tệp nguồn nào của thư viện của tôi, khai báo nó như là bên ngoài trong phần đầu. Nhưng làm thế nào tôi có thể tạo logger tự động khi một ứng dụng kết nối với thư viện?

Tôi biết rằng trong các tệp DLL cho Windows, có một thứ như REASON_FOR_CALL == PROCESS_ATTACH; có một điều tương tự trong Linux?

Trả lời

16

Trong C++ trong Linux, các biến toàn cục sẽ được tạo tự động ngay khi thư viện được tải. Vì vậy, đó có lẽ là cách dễ nhất để đi.

Nếu bạn cần một chức năng tùy ý để được gọi khi thư viện được nạp, sử dụng thuộc tính constructor cho GCC: chức năng

__attribute__((constructor)) void foo(void) { 
    printf("library loaded!\n"); 
} 

Constructor được gọi bởi các mối liên kết động khi thư viện được nạp. Đây thực sự là cách khởi tạo toàn cục C++.

+0

Điều này cũng hợp lệ cho các thư viện C. Ngoài ra còn có '__attribute __ ((destructor))' cho một hàm được gọi khi thư viện được giải nén –

+0

... và thuộc tính này không liên quan gì đến việc xây dựng đối tượng? – einpoklum

+0

@einpoklum, phải, điều này hầu như không liên quan đến xây dựng đối tượng. Bạn có thể sử dụng nó trong C, không có đối tượng. Điều đó nói rằng, C++ sử dụng nội bộ này để gọi các nhà xây dựng và các destructors của các đối tượng toàn cầu. –

10

Nếu bạn muốn mã của bạn để được cầm tay có lẽ bạn nên thử một cái gì đó như thế này:

namespace { 
    struct initializer { 
    initializer() { 
     std::cout << "Loading the library" << std::endl; 
    } 

    ~initializer() { 
     std::cout << "Unloading the library" << std::endl; 
    } 
    }; 
    static initializer i; 
} 
+1

Bạn có thể giải thích tại sao câu trả lời của bạn tốt hơn là chỉ sử dụng hình cầu và không làm bất cứ điều gì đặc biệt về nó? – einpoklum

+0

Nó cung cấp cho bạn một destructor để dọn dẹp. Ngoài ra, destructor sẽ luôn được gọi khi thoát khỏi chương trình ngay cả khi nó là một ngoại lệ hoặc một lối thoát được lên kế hoạch bình thường. –

3

Sử dụng toàn cầu (hoặc một địa phương tĩnh gói lên trong một hàm) là tốt đẹp ... nhưng sau đó bạn nhập vào vùng đất của sự thất bại khởi tạo tĩnh (và sự hủy diệt thực sự cũng không đẹp).

Tôi khuyên bạn nên xem qua triển khai Singleton của Loki.

Có các chính sách trọn đời khác nhau, một trong số đó là Phoenix và sẽ giúp bạn tránh thất bại này.

Khi bạn ở đó, hãy đọc Thiết kế hiện đại C++ giải thích các vấn đề mà Singleton gặp phải cũng như sử dụng cho các chính sách khác nhau.

+1

+1 để sử dụng từ "thất bại" để mô tả những gì người khác có thể gọi là "địa ngục". :) – unwind

+2

Fiasco là một khái niệm ngu ngốc được đưa lên bởi trang web khủng khiếp C++ FAQ. Nó không phải là một thất bại và bình luận thậm chí không liên quan trong phạm vi này vì dường như không có sự liên kết nào giữa các biến toàn cầu. –

+2

Cho phép tôi không đồng ý với Martin, nhưng sự cám dỗ để ghi lại việc xây dựng hoặc hủy diệt các quả cầu là có thật. –

Các vấn đề liên quan