Jump to content
  • Advertisement
mark_braga

C++ How would I throw a compiler error if the new function is used?

This topic is 465 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to prohibit the use of new, delete in one of my projects. There are still instances where I need the placement new operator to construct things like containers which need a constructor call.

So I cannot just use the old #define new Error trick. I looked at static_assert but that will throw an error irrespective of whether the function is used or not. In addition, I can't use the #pragma deprecated because it only generates a warning and we have warnings in our project which are out of my control.

So is there any other way to throw a compiler error when a function is used? I am talking about the global new and delete operators.

Thank you

Edited by mark_braga

Share this post


Link to post
Share on other sites
Advertisement

Do you have to have a compile-time error? You can probably override global new and delete and not implement them (I think) which would at least give you a linker error. This also avoids the macro magic which would clobber placement new.

Share this post


Link to post
Share on other sites

If you are OK with a warning instead of an error, you could use:

[[deprecated("because")]] void func(void)
{
}

Unfortunately attributes aren't unversally supported yet, so you'd have to fallback to vendor-specific implementations ie. for MSVC; which works quite similar though:

__declspec(deprecated("** this is a deprecated function **")) void func2(int) {}  

 

Share this post


Link to post
Share on other sites
4 hours ago, mark_braga said:

I want to prohibit the use of new, delete in one of my projects. There are still instances where I need the placement new operator to construct things like containers which need a constructor call.

So I cannot just use the old #define new Error trick.

[Edit:] Oops, I misread your original statement about needing *placement* new, so this post doesn't actually help you.

new and delete have pretty simple implementations (based off of malloc() and free(), but with constructor/destructor calls and a few other niceties). You could grab an implementation off the web, maybe even your own compiler's copy if the licensing permits, and give them different function names (e.g. "MyDeleteFunc()").

I just tossed this together and it compiled and ran fine, though I may have made a mistake somewhere:
(feel free to take it as your own, though at your own risk =P)

Spoiler

namespace Memory
{
    template<typename Type, typename ...Args>
    Type *Allocate(Args&& ...args)
    {
        //Allocate memory using 'malloc'.
        Type *ptr = static_cast<Type*>(malloc(sizeof(Type)));
        assert(ptr && "We're probably out of memory.");
        
        //Manually call constructor, forwarding the arguments to the constructor.
        new (ptr) Type(std::forward<Args>(args)...);
        
        //Return the pointer.
        return ptr;
    }
    
    template<typename Type>
    void Deallocate(Type* &ptr) //Reference to a pointer. Huh, never had to use that before.
    {
        //Comment this assert out if you like the ability to pass null to 'delete'.
        assert(ptr && "Trying to allocate an already NULL pointer.");
        
        //Call the destructor manually.
        ptr->~Type();
         
        //Deallocate the memory.
        free(ptr);
      
        //Nullify the pointer (we got a reference to a pointer, so this is nulling the pointer that was passed into the function).
        //Comment this line out if you want to do the nulling yourself.
        ptr = nullptr;
    }
    
} //End of namespace.
	

 

Usage:

MyClass *myClass = Memory::Allocate<MyClass>("Hello", 357);
Memory::Deallocate(myClass);

Here's where I tested it.

When some people reimplement new(), they also add things like leak detection and other features.

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
25 minutes ago, ApochPiQ said:

As I understand it, the point isn't to reinvent new, it's to prevent it from being used at all.

Yea, I definitely misread it. I thought he was asking for a way to disable new for most of the code, but still make it available for his internal classes, so I was suggesting disabling and reimplementing under a new name.

However, he was asking for a way to disable new, but keep *placement* new.

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

Some googling turned up the pragmas "push_macro"/"pop_macro", which is compatible with Visual Studio, GCC, and Clang. This means you can do this:

//===========================================
#define new static_assert(false, "'new' is not available");

#pragma push_macro("new")
#undef new

template<typename Type, typename ...Args>
void priv_PlacementNew(Type *ptr, Args&& ...args)
{
    new (ptr) Type(std::forward<Args>(args)...);
} 

#pragma pop_macro("new")
//===========================================

Here's the Ideone test, which works how I think you are asking.

(or you can push_macro/undef/pop_macro manually each time you want to use placement new)

In practice, you'll want to define 'new' via a compiler parameter, or it won't cover your entire project.

Ofcourse, in real true practice, there's a limit to how far you should go to bubblewrap things to prevent programmers from shooting themselves, and I personally think this crosses that limit.

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!