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

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

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Forum Statistics

    • Total Topics
      628722
    • Total Posts
      2984397
  • Similar Content

    • By Josheir
      void update() { if (thrust) { dx += cos(angle*DEGTORAD)*.02; dy += sin(angle*DEGTORAD)*.02; } else { dx*=0.99; dy*=0.99; } int maxSpeed = 15; float speed = sqrt(dx*dx+dy*dy); if (speed>maxSpeed) { dx *= maxSpeed/speed; dy *= maxSpeed/speed; } x+=dx; y+=dy; . . . } In the above code, why is maxSpeed being divided by the speed variable.  I'm stumped.
       
      Thank you,
      Josheir
    • By Benjamin Shefte
      Hey there,  I have this old code im trying to compile using GCC and am running into a few issues..
      im trying to figure out how to convert these functions to gcc
      static __int64 MyQueryPerformanceFrequency() { static __int64 aFreq = 0; if(aFreq!=0) return aFreq; LARGE_INTEGER s1, e1, f1; __int64 s2, e2, f2; QueryPerformanceCounter(&s1); s2 = MyQueryPerformanceCounter(); Sleep(50); e2 = MyQueryPerformanceCounter(); QueryPerformanceCounter(&e1); QueryPerformanceFrequency(&f1); double aTime = (double)(e1.QuadPart - s1.QuadPart)/f1.QuadPart; f2 = (e2 - s2)/aTime; aFreq = f2; return aFreq; } void PerfTimer::GlobalStart(const char *theName) { gPerfTimerStarted = true; gPerfTotalTime = 0; gPerfTimerStartCount = 0; gPerfElapsedTime = 0; LARGE_INTEGER anInt; QueryPerformanceCounter(&anInt); gPerfResetTick = anInt.QuadPart; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void PerfTimer::GlobalStop(const char *theName) { LARGE_INTEGER anInt; QueryPerformanceCounter(&anInt); LARGE_INTEGER aFreq; QueryPerformanceFrequency(&aFreq); gPerfElapsedTime = (double)(anInt.QuadPart - gPerfResetTick)/aFreq.QuadPart*1000.0; gPerfTimerStarted = false; }  
      I also tried converting this function (original function is the first function below and my converted for gcc function is under that) is this correct?:
      #if defined(WIN32) static __int64 MyQueryPerformanceCounter() { // LARGE_INTEGER anInt; // QueryPerformanceCounter(&anInt); // return anInt.QuadPart; #if defined(WIN32) unsigned long x,y; _asm { rdtsc mov x, eax mov y, edx } __int64 result = y; result<<=32; result|=x; return result; } #else static __int64 MyQueryPerformanceCounter() { struct timeval t1, t2; double elapsedTime; // start timer gettimeofday(&t1, NULL); Sleep(50); // stop timer gettimeofday(&t2, NULL); // compute and print the elapsed time in millisec elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms return elapsedTime; } #endif Any help would be appreciated, Thank you!
    • By mister345
      Hi, I'm building a game engine using DirectX11 in c++.
      I need a basic physics engine to handle collisions and motion, and no time to write my own.
      What is the easiest solution for this? Bullet and PhysX both seem too complicated and would still require writing my own wrapper classes, it seems. 
      I found this thing called PAL - physics abstraction layer that can support bullet, physx, etc, but it's so old and no info on how to download or install it.
      The simpler the better. Please let me know, thanks!
    • By lawnjelly
      It comes that time again when I try and get my PC build working on Android via Android Studio. All was going swimmingly, it ran in the emulator fine, but on my first actual test device (Google Nexus 7 2012 tablet (32 bit ARM Cortex-A9, ARM v7A architecture)) I was getting a 'SIGBUS illegal alignment' crash.
      My little research has indicated that while x86 is fine with loading 16 / 32 / 64 bit values from any byte address in memory, the earlier ARM chips may need data to be aligned to the data size. This isn't a massive problem, and I see the reason for it (probably faster, like SIMD aligned loads, and simpler for the CPU). I probably have quite a few of these, particular in my own byte packed file formats. I can adjust the exporter / formats so that they are using the required alignment.
      Just to confirm, if anyone knows this, is it all 16 / 32 / 64 bit accesses that need to be data size aligned on early android devices? Or e.g. just 64 bit size access? 
      And is there any easy way to get the compiler to spit out some kind of useful information as to the alignment of each member of a struct / class, so I can quickly pin down the culprits?
      The ARM docs (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html) suggest another alternative is using a __packed qualifier. Anyone used this, is this practical?
    • By Josheir
      In the following code:

       
      Point p = a[1]; center of rotation for (int i = 0; I<4; i++) { int x = a[i].x - p.x; int y = a[i].y - p.y; a[i].x = y + p.x; a[i].y = - x + p.y; }  
      I am understanding that a 90 degree shift results in a change like:   
      xNew = -y
      yNew = x
       
      Could someone please explain how the two additions and subtractions of the p.x and p.y works?
       
      Thank you,
      Josheir
  • Popular Now