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

Started by
7 comments, last by Servant of the Lord 6 years, 7 months ago

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

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.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Yeah but then you cant put a pretty message saying "Please dont use new" :)

 

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) {}  

 

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.

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

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

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.

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.

This topic is closed to new replies.

Advertisement