2010-08-13 61 views
19

Một số mã của tôi vẫn sử dụng malloc thay vì new. Lý do là vì tôi sợ sử dụng new vì nó ném ngoại lệ, thay vì trả lại NULL, mà tôi có thể dễ dàng kiểm tra. Gói mọi cuộc gọi đến new trong một số try{}catch(){} cũng không có vẻ tốt. Trong khi sử dụng malloc tôi chỉ có thể thực hiện if (!new_mem) { /* handle error */ }.Có thể sử dụng một con trỏ thông minh C++ cùng với malloc của C không?

Vì vậy, tôi có một câu hỏi. Tôi có thể sử dụng con trỏ thông minh cùng với malloc không?

Cái gì như:

SmartPointer<Type> smarty = malloc(sizeof(Type)); 

Something như thế này.

Điều này có khả thi không?

Cảm ơn, Boda Cydo.

+2

Nếu bạn muốn mới đến bây giờ ném một ngoại lệ và chỉ trả về NULL bạn có thể sử dụng: Loại * bla = new (std :: nothrow) Type() ;. Tôi nghĩ rằng nó tốt hơn để sử dụng std :: nothrow hơn malloc vì sau này không gọi constructor. –

+1

Bạn sẽ làm gì trong mã xử lý lỗi để bù đắp cho việc không nhận được bộ nhớ? Thông thường thử nghiệm là nếu phân bổ làm việc sau đó làm việc. Nếu nó không xuất cảnh với một mã lỗi (đó là một cách compilcated đi qua kiểm soát sao lưu ngăn xếp). –

Trả lời

31

Nếu bạn đang sử dụng shared_ptr hoặc unique_ptr, bạn có thể chỉ định deleter tùy chỉnh. Ví dụ,

struct free_delete 
{ 
    void operator()(void* x) { free(x); } 
}; 

Điều này có thể được sử dụng với shared_ptr như vậy:

std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete()); 

Nếu bạn đang sử dụng unique_ptr, các deleter là một phần của loại 's unique_ptr, vì vậy deleter cần phải được được chỉ định làm đối số mẫu:

std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int))); 

Tuy nhiên, tốt hơn nên sử dụng ngoại lệ chính xác, thay vì tránh chúng, khi viết C++, đặc biệt là với r không phân biệt thất bại. Trong hầu hết các trường hợp, bạn không thể khôi phục thành công từ lỗi phân bổ trong hàm đang cố gắng thực hiện phân bổ, vì vậy các ngoại lệ có thể giúp bạn xử lý lỗi mà bạn thực sự có khả năng xử lý nó.

+0

Bạn cũng có thể chuyển trực tiếp 'free':' auto myPointer = std :: unique_ptr (..., miễn phí) ' –

+2

@PatrickChilton Lưu ý rằng nếu bạn làm điều này,' unique_ptr' sẽ lớn hơn gấp đôi. –

1

Phụ thuộc vào những gì SmartPointer thực hiện khi hủy. Nếu bạn có thể chỉ định free làm người deallocator, điều đó có thể hoạt động. Ví dụ, boost :: shared_ptr cho phép bạn chỉ định một deleter.

Tôi không chú ý đầy đủ đến lý do bạn muốn điều này. Tôi đồng ý với các câu trả lời khác mà sử dụng nothrow new là một ý tưởng tốt hơn nhiều.

1

Có thể sử dụng malloc với con trỏ thông minh (bạn phải truyền giá trị trả về để nhắm mục tiêu loại con trỏ, mặc dù và cung cấp tùy chỉnh deallocator). Nhưng lựa chọn tốt hơn là sử dụng nothrow phiên bản của nhà điều hành new.

http://www.cplusplus.com/reference/std/new/nothrow/

9

Bạn có thể sử dụng nothrow từ khóa với các nhà điều hành mới, mà sẽ trả về NULL đúng hơn là ném một ngoại lệ. Để biết chi tiết, hãy xem liên kết bên dưới: http://www.cplusplus.com/reference/std/new/nothrow/

+1

Sử dụng 'nothrow' là một thực tế phổ biến? (Bởi vì tôi đã không thực sự nhìn thấy cá nhân sử dụng nothrow trong thực tế thực tế bản thân mình.) – bodacydo

+7

Đây là cách phổ biến nhất để sử dụng 'mới' khi bạn không muốn nó ném một ngoại lệ. Nhưng không, nó là phổ biến hơn để chỉ sử dụng 'mới' và làm việc * với * xử lý ngoại lệ. Nếu phân bổ không thành công, bạn thường không thể làm gì nhiều về nó, do đó, để cho một tuyên truyền ngoại lệ là một cách khá sạch sẽ để thoát ra một cách duyên dáng. – jalf

1

Mã nào có trong /* handle error */? Có bất cứ điều gì bạn thực sự có thể làm với một lỗi out-of-bộ nhớ? Tôi chỉ cho phép ứng dụng chấm dứt với một ngăn xếp cuộc gọi (lõi dump) vì vậy tôi có một ý tưởng ít nhất một nơi có thể có thể gây ra vấn đề.

Sử dụng malloc để cấp phát bộ nhớ cho các lớp học C++ và các đối tượng không phải là một ý tưởng tốt bởi vì nó sẽ không đảm bảo rằng các nhà thầu được mời gọi, có thể để lại cho bạn với các lớp học chưa được khởi tạo mà thậm chí có thể sụp đổ nếu họ có phương pháp ảo.

Chỉ cần sử dụng newdelete và đừng lo lắng về việc bắt ngoại lệ, sau khi hết bộ nhớ IS là trường hợp ngoại lệ và không nên xảy ra trong các lần chạy ứng dụng thông thường.

+0

Có một số tình huống mà bạn _can_ xử lý lỗi. Ví dụ, tính toán số tham chiếu bộ nhớ (ví dụ mô phỏng) có thể dễ dàng thoát ra khỏi bộ nhớ trên các máy yếu, nhưng trong trường hợp này bạn có thể dừng ngay lập tức và hiển thị lỗi thay vì bị lỗi. – Yury

1

Sử dụng nothrow.

Nothrow liên tục

giá trị không đổi này được sử dụng như là một đối cho nhà điều hành mới và điều hành mới [] để cho biết rằng các chức năng này sẽ không ném một ngoại lệ trên thất bại, nhưng trả về một null con trỏ thay thế.

char* p = new (nothrow) char [1048576]; 
if (p==NULL) cout << "Failed!\n"; 
else { 
    cout << "Success!\n"; 
    delete[] p; 
} 
3

Giải pháp tốt nhất là sử dụng new (std::nothrow) Type. Điều này sẽ hoạt động giống như new Type, nhưng sẽ cung cấp cho null thay vì ném nếu nó không thành công. Việc này sẽ dễ dàng hơn nhiều so với việc cố gắng thực hiện malloc hoạt động như new.

Nếu bạn thực sự phải sử dụng malloc, sau đó nhớ để xây dựng và hủy đối tượng một cách chính xác:

void* memory = malloc(sizeof(Type)); 
Type* object = new (memory) Type; 
object->~Type(); 
free(object); // or free(memory) 

Bạn có thể sử dụng điều này với một số gợi ý thông minh bằng cách cho nó một deleter tùy chỉnh:

void malloc_deleter(Type* object) 
{ 
    object->~Type(); 
    free(object); 
} 

if (void* memory = malloc(sizeof(Type))) 
{ 
    Type* object = new (memory) Type; 
    std::shared_ptr<Type> ptr(object, malloc_deleter); 
    DoStuff(ptr); 
} 

Nhưng điều này sẽ đơn giản hơn nhiều khi sử dụng tính năng không ném mới:

if (Type* object = new (std::nothrow) Type) 
{   
    std::shared_ptr<Type> ptr(object); 
    DoStuff(ptr); 
} 
+0

Sử dụng malloc có lợi thế bổ sung cho phép bạn sử dụng realloc: http://stackoverflow.com/a/33706568/1858225 –

1

Tôi có một câu hỏi.

Điều gì sẽ xảy ra nếu "Loại" là loại mà người tạo có thể ném? Trong trường hợp đó, người ta vẫn cần xử lý các ngoại lệ trong một khối try/catch.

Vì vậy, bạn nên từ bỏ phương pháp tiếp cận dựa trên ngoại lệ?

Tôi có thể nói rằng người ta có thể sử dụng mẫu thiết kế Phương thức nhà máy/phương pháp nhà máy trừu tượng và có tất cả các tệp mới trong tập hợp/không gian tên/lớp tương đối ít hơn, thay vì nằm rải rác khắp nơi. Điều đó cũng có thể giúp hạn chế việc sử dụng khối try/catch đối với một mã tương đối nhỏ hơn.

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