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

橙三吉。 提交于 2021-02-07 21:54:46

问题


I know I can prevent ordinary heap allocation of custom class and its descendants by making the class's operator new private, but is there any way to prevent a user of a library from calling std::make_shared on a custom class (or its descendants)? Apparently, simply making the operator new private in a class does not stop it.

Note that I do not want to completely prevent shared pointers from being created by any means, as I intend to still be able to produce a std::shared_ptr for my custom class by calling a static generator method, but I still want to prevent others from trying to call std::make_shared on my class directly.

EDIT:

To address queries below, my ultimate goal here is a flexible and reusable mechanism for extracting a shared_ptr from a raw pointer. std::enable_shared_from_this is regretfully not very friendly when it comes to inheritance and especially multiple inheritance.

Also, because I am intending for this to be used as in a template class using CRTP, it would complicate matters somewhat for the a child class T to need to explicitly make the templated parent class it inherits from a friend so that it can access otherwise private constructors.


回答1:


Blocking user heap allocation of a type T is not actually a thing you can do in C++. At least, not so long as they can create Ts. Even if you manage to forbid make_shared<T>, your user can still do this:

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

The T inside of *opt is definitely on the heap. Any number of other similar gymnastics can achieve the same effect. You can even call make_shared<optional<T>>, with the in_place parameters.

So long as T has publicly accessible constructors, or there is any publicly accessible way of constructing a T that returns a prvalue of it, users can find ways to store that T on the heap.

So the only way to prevent this is to make all of your constructors private (whether directly with private or a private key type or whatever other mechanism you want) and only provide publicly accessible functions that return shared_ptr<T>s.

Outside of macros, there is no C++ mechanism that just causes a type to work this way. It must be done individually, for each type that you want to work this way.




回答2:


This is not specific for std::shared_ptr, but you can make the constructor private and that way force all instances of the class to get generated from your static method.

#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();
}

You can also use deduplicators suggestion and use a private key to make the constructor inaccessible outside of the 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();
}



回答3:


Above answers are better solutions to the problem. But, if you're trying to not let the make_shared make new instance of your class, maybe this is helpful.

#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' gets a object address while 'q' doesn't.

Note: requires -fpermissive option in the compiler.



来源:https://stackoverflow.com/questions/58015983/how-to-block-usage-of-stdmake-sharedt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!