2008-10-29 38 views
10

Tôi có một số char* p, trỏ đến một chuỗi \0 -terminated. Làm cách nào để tạo một C++ string từ nó theo cách an toàn ngoại lệ?tạo std :: chuỗi từ char * một cách an toàn

Dưới đây là một phiên bản không an toàn:

string foo() 
{ 
    char *p = get_string(); 

    string str(p); 
    free(p); 
    return str; 
} 

Một giải pháp hiển nhiên sẽ là thử-catch - cách nào dễ dàng hơn?

Trả lời

25

Bạn có thể sử dụng shared_ptr từ C++11 hoặc Boost:

string 
foo() 
{ 
    shared_ptr<char> p(get_string(), &free); 
    string str(p.get()); 
    return str; 
} 

này sử dụng một tính năng rất cụ thể của shared_ptr không có sẵn trong auto_ptr hoặc bất cứ điều gì khác, cụ thể là khả năng xác định một deleter tùy chỉnh; trong trường hợp này, tôi đang sử dụng free làm deleter.

+0

có, ngoại trừ việc chúng tôi không thường sử dụng Boost, nhưng tôi có thể tạo ra một lớp như vậy bản thân mình. Cảm ơn –

+0

Đó là ví dụ về SWEET. – Allbite

1

Yup - thư giãn dựa trên chồng. C++ Thiết kế hiện đại có giải pháp chung nhưng trong trường hợp này, bạn có thể sử dụng

struct Cleanup { 
     void* toFree; 
     Cleanup(void* toFree) : toFree(toFree) {} 
     ~Cleanup() { free(toFree); } 
    private: 
     Cleanup(Cleanup&); 
     void operator=(Cleanup&); 
}; 

Không có vấn đề gì xảy ra với std :: string của bạn, miễn phí (toFree) sẽ được gọi khi đối tượng Cleanup của bạn đi ra khỏi phạm vi.

1

Vâng, p không trỏ đến chuỗi 0 chấm dứt nếu get_string() trả về NULL; đó là vấn đề ở đây, vì các nhà xây dựng std::string đưa con trỏ tới chuỗi 0 chấm dứt C không thể xử lý NULL, mà càng nhiều chuỗi C chấm dứt 0 là hai chục chuối.

Vì vậy, nếu get_string() là chức năng của riêng bạn, thay vì chức năng thư viện, thì có thể bạn nên đảm bảo rằng nó không thể trả về NULL. Ví dụ, bạn có thể để cho nó trả lại chính số std::string được tìm kiếm, vì nó biết trạng thái của chính nó. Nếu không, tôi muốn làm điều này, sử dụng Cleanup từ this answer như một helper để đảm bảo rằng p không thể bị rò rỉ (theo đề nghị của Martin York trong một chú thích):

string foo() 
{ 
    const char* p = get_string(); 
    const Cleanup cleanup(p); 
    const std::string str(p != NULL ? p : ""); 

    return str; 
} 
+0

Ngoài mã không biên dịch (Xem L ""). Nó không ngoại lệ an toàn. Bạn không đảm bảo rằng p sẽ được phát hành. –

+0

Ah! Xin lỗi về điều đó - Tôi chỉ phát triển cho các thiết bị dựa trên Windows CE, và ở đó chúng tôi chỉ có chuỗi Unicode, vì vậy tiền tố 'L' được gắn vào cột sống của tôi khi tôi viết mã. Trường hợp đó hiện đã được sửa. –

+0

Phew! Bây giờ rò rỉ cũng biến mất. Cảm ơn đã chỉ ra điều đó. –

0

Chúng tôi thường sử dụng ScopeGuard cho những trường hợp này:

string foo() 
{ 
    char *p = get_string(); 
    ScopeGuard sg = MakeGuard(&free, p); 
    string str(p); 
    return str; 
} 
3

Tôi có thể hỏi bạn ngoại lệ bạn mong đợi trong ví dụ của mình không?

Trên nhiều nền tảng (Linux, AIX) mới hoặc malloc sẽ không bao giờ bị lỗi và ứng dụng của bạn sẽ bị hệ điều hành xóa nếu bạn hết bộ nhớ.

Xem liên kết này: What happens when Linux runs out of memory.

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