std::make_shared可以和operator new协同工作吗?

问题描述 投票:0回答:1

std::make_shared
使用
::new
,因此如果使用特定于类的
operator new
设置了任何特殊行为,它将与
std::shared_ptr<T>(new T(args...))
不同。

因此,对于下面的类,如果我们使用

std::make_shared<MyClass>()
,那么
Tracker
无法观察到任何内容。

class MyClass
{
public:
    static void operator delete(void * ptr, std::size_t sz)
    {
        Tracker::deallocated(sz);
        ::operator delete(ptr);
    }

    static void operator delete[](void * ptr, std::size_t sz)
    {
        Tracker::deallocated(sz);
        ::operator delete[](ptr);
    }
    static void * operator new(std::size_t sz)
    {
        Tracker::allocated(sz);
        return ::operator new(sz);
    }

    static void * operator new[](std::size_t sz)
    {
        Tracker::allocated(sz);
        return ::operator new[](sz);
    }
}

但是,我也不想要定制的

::new
。所以我想知道我可以做什么来跟踪所有分配/解除分配的内存
MyClass

c++ new-operator make-shared
1个回答
0
投票

正如@PepijnKramer 指出的,你最好使用

std::allocate_shared
而不是
std::make_shared
。它有助于区分不同的关注点。困难的部分是定义一个
tracking_allocator
模板类作为第一个参数传递给
std::allocate_shared
:

#include <memory>
#include <type_traits>

template<typename T>
struct tracking_allocator{

    template<typename U>
    struct rebind // this is a must for use with 'std::allocate_shared'
    { using other = struct tracking_allocator<U>; };

    static T*  allocate(std::size_t n){
        static_assert(std::is_empty_v<tracking_allocator>, "allocator must be empty class");
        return /*alloc and track 'n' elements of 'T'*/;
    }; //! allocate(n);

    static void deallocate(T* ptr, std::size_t n){
        return /*dealloc and track 'n' elements of 'T' at starting at 'ptr'*/;
    }; //! deallocate(ptr,n);

    static void construct(T* ptr, auto&& ... args){
        // do some tracking ...
        std::construct_at(ptr, std::forward<Args>(args)...);
    }; //! construct(ptr,args...);

    static void destroy(T* ptr){
        // do some tracking ...
        std::destroy_at(ptr);
        // do more tracking ...
    }; //! destroy(ptr);

}; //! tracking_allocator<T>;

现在您可以使用

tracking_allocator
作为选择加入:

constexpr bool is_debug_mode = /*use std or tracking alloc*/;

using my_allocator = std::conditional_t<
                          is_debug_mode,
                          tracking_allocator<myclass>,
                          std::allocator<myclass>>;

auto myptr=std::allocate_shared<myclass>(my_allocator{});

您的跟踪逻辑现在完全独立于类定义,并且可以通过

is_debug_mode
打开和关闭。您还可以利用
std::allocate_shared
的分配器参数:

auto my_next_ptr=std::allocate_shared<myclass>(std::allocator<myclass>{});

但这不如主要方法灵活。因此,为了方便起见,您可以定义您选择的 make 函数:

auto make_myclass()
{ return std::allocate_shared(my_allocator{}); };

auto myptr = make_myclass();

您可以制作上述任何类和函数模板;但作为说明,这会让这篇文章变得过于复杂。

© www.soinside.com 2019 - 2024. All rights reserved.