2012-12-29 13 views
16

Cân nhắc this code:Có std :: make_shared() sử dụng phân bổ tùy chỉnh?

#include <memory> 
#include <iostream> 


class SomeClass { 
public: 
    SomeClass() { 
     std::cout << "SomeClass()" << std::endl; 
    } 

    ~SomeClass() { 
     std::cout << "~SomeClass()" << std::endl; 
    } 

    void* operator new(std::size_t size) { 
     std::cout << "Custom new" << std::endl; 
     return ::operator new(size); 
    } 

    void operator delete(void* ptr, std::size_t size) { 
     std::cout << "Custom delete" << std::endl; 
     ::operator delete(ptr); 
    } 
}; 



int main() { 
    std::shared_ptr<SomeClass> ptr1(new SomeClass); 
    std::cout << std::endl << "Another one..." << std::endl << std::endl; 
    std::shared_ptr<SomeClass> ptr2(std::make_shared<SomeClass>()); 
    std::cout << std::endl << "Done!" << std::endl << std::endl; 
} 

Đây là sản lượng của nó:

Custom new 
SomeClass() 

Another one... 

SomeClass() 

Done! 

~SomeClass() 
~SomeClass() 
Custom delete 

Rõ ràng, std::make_shared() đã không gọi cho các nhà điều hành new - nó sử dụng một cấp phát tùy chỉnh. Đây có phải là hành vi tiêu chuẩn cho std::make_shared() không?

Trả lời

16

Vâng, đây là hành vi tiêu chuẩn. Từ tiêu chuẩn (§20.7.2.2.6 tạo shared_ptr):

Effects: bộ nhớ Phân bổ thích hợp cho một đối tượng kiểu T và xây dựng một đối tượng trong bộ nhớ thông qua vị trí biểu hiện mới ::new (pv) T(std::forward<Args>(args)...).

Điều này cho phép make_shared cấp phát bộ nhớ cho cả đối tượng và cấu trúc dữ liệu cho chính con trỏ được chia sẻ ("khối điều khiển") trong một phân bổ duy nhất, vì lý do hiệu quả.

Bạn có thể sử dụng std::allocate_shared nếu bạn muốn kiểm soát việc phân bổ bộ nhớ đó.

+4

'std :: allocate_shared (const A &, Args && ...)' cũng đáng được đề cập đến. Đối số đầu tiên là bộ cấp phát để gọi 'A :: allocate'. –

2

Để mở rộng câu trả lời đúng Mat của, make_shared thường được thực hiện bằng cách phân bổ một đối tượng có chứa các shared_ptr đếm tham khảo và một bộ đệm byte uninitialized:

template<typename T> 
    struct shared_count_inplace 
    { 
    long m_count; 
    long weak_count; 
    typename std::aligned_storage<sizeof(T)>::type m_storage; 
    // ... 
    }; 

Đây là loại mà sẽ được cấp phát trên heap , không phải loại của bạn, vì vậy loại của bạn là new không được gọi. Sau đó, loại của bạn sẽ được tạo bằng cách sử dụng vị trí new tại vị trí (void*)&m_storage.