You cannot ensure that class objects are always on the stack, making only operators available: any object that can be constructed on the stack can also be embedded as a member in another object. Although your source class may struggle to be allocated on the heap, a class that will not contain. I would think that this happens in the case of boost::make_shared() : inside it, probably, some record is selected that contains both the administration data and the selected object. Alternatively, it can use a distribution function from a sort of allocator that does not match the type operator new() , but uses its own operator new() overload instead.
I'm not sure if it is possible to prevent heap allocation (at least when the object is embedded in another object), but any approach that does this should make inaccessible constructors (most likely private ) and use something like factory functions, maybe combined with moving. On the other hand, if you can move an object, you have an available constructor, and nothing prevents the object from being moved to an object on the heap.
If you specifically want to prevent the use of std::make_shared() for a particular type (or boost::make_shared() , although I cannot quote the rules for specializing the latter), you can specialize std::make_shared() : according to 17.6.4.2. 1 [namespace.std], clause 1, the user can specialize in any template (unless otherwise specified), if it is associated with a custom type. Thus, you can prohibit the use of A with std::make_shared() :
class A { public: A(); A(int); }; namespace std { template <> std::shared_ptr<A> make_shared<A>() = delete; template <> std::shared_ptr<A> make_shared<A, int>(int&&) = delete; } namespace boost { template <> boost::shared_ptr<A> make_shared<A>() = delete; template <> boost::shared_ptr<A> make_shared<A, int>(int&&) = delete; }
Obviously, if you have several constructors in A , you may need to add additional specializations .... and if your type is a class template or your constructor as a template, you are out of luck: you cannot partially specialize function templates.
Regarding your question about placing new (which may or may not be used by make_shared() ): The signatures of new (and delete ) are as follows:
void* operator new(size_t, void*) noexcept; void* operator new[](size_t, void*) noexcept; void operator delete(void*, void*) noexcept; void operator delete[](void*, void*) noexcept;
(see clause 18.6 [support.dynamic]). I doubt that making them inaccessible will help you.