如何阻止使用 std::make_shared<T>

how to block usage of std::make_shared<T>

我知道我可以通过将 class 的 operator new 设为私有来防止自定义 class 及其后代的普通堆分配,但是有什么方法可以防止用户在自定义 class(或其后代)上调用 std::make_shared 的库? Apparently,只是在 class 中将 operator new 设为私有并不能阻止它。

请注意,我不想完全阻止以任何方式创建共享指针,因为我仍打算通过调用静态方法为我的自定义 class 生成 std::shared_ptr生成器方法,但我仍然想阻止其他人尝试直接在我的 class 上调用 std::make_shared

编辑:

为了解决下面的问题,我的最终目标是一种灵活且可重用的机制,用于从原始指针中提取 shared_ptr。 std::enable_shared_from_this 遗憾的是在继承尤其是多重继承方面不是很友好。

此外,因为我打算将其用作模板 class 使用 CRTP,这会使 child class 的事情变得有些复杂T 需要显式地使模板化 parent class 它继承自朋友,以便它可以访问其他私有构造函数。

这不是特定于 std::shared_ptr,但您可以将构造函数设为私有,这样可以强制 class 的所有实例从您的静态方法生成。

#include <iostream>
#include <memory>

class Foo {
    private:
    Foo() = default;

    public:
    static std::shared_ptr<Foo> make() {
        return std::shared_ptr<Foo>(new Foo);
    }
};

int main() {
    //Foo f1;
    //auto f2 = std::make_shared<Foo>(); 
    //above does not work since the constructor is private
    auto h = Foo::make();
}

您还可以使用重复数据删除器建议并使用私钥使构造函数在 class 之外无法访问。

#include <iostream>
#include <memory>

class Foo {
    private:
    struct FooKey {};

    public:
    Foo(FooKey) {};

    static std::shared_ptr<Foo> make() {
        return std::make_shared<Foo>(FooKey{});
    }
};

int main() {
    //Foo f1{Foo::FooKey{}};
    //auto f2 = std::make_shared<Foo>(Foo::FooKey{}); 
    //above does not work since Foo::FooKey is private
    auto h = Foo::make();
}

阻止类型T 的用户堆分配实际上不是您可以在C++ 中执行的操作。至少,只要他们可以创建 Ts。即使您设法禁止 make_shared<T>,您的用户仍然可以这样做:

unique_ptr opt = new optional<T>;
opt->emplace(...);

*opt里面的T肯定在堆上。任何数量的其他类似体操都可以达到相同的效果。您甚至可以使用 in_place 参数调用 make_shared<optional<T>>

只要 T 具有可公开访问的构造函数,或者存在任何可公开访问的构造 T 且 return 是它的纯右值的方法,用户就可以找到存储的方法T 在堆上。

所以防止这种情况的唯一方法是将所有构造函数设为私有(无论是直接使用 private 还是 private 密钥类型或您想要的任何其他机制)并且只提供可公开访问的return shared_ptr<T>s.

的函数

除了宏之外,没有任何 C++ 机制可以使类型以这种方式工作。对于您希望以这种方式工作的每种类型,必须单独完成。

以上回答是解决问题的较好方法。但是,如果您不想让 make_shared 创建您的 class 的新实例,也许这会有所帮助。

#include <iostream>
#include <memory>
using namespace std;

class A {
private:
    void * operator new(size_t size) {}
};

template<> shared_ptr<A> make_shared() {
    cout << "this was called.\n";
    return nullptr;
}

int main() {
    A a;
    shared_ptr<A> p = make_shared<A>(a);
    shared_ptr<A> q = make_shared<A>();
    cout << "p: " << p << endl;
    cout << "q: " << q << endl;

    return 0;
}

'p' 获取对象地址而 'q' 没有。

注意:编译器中需要 -fpermissive 选项。