How to poison an identifier in VC++?

2020-06-16 02:55发布

问题:

Function poisoning is very useful technique in C++.

In general it refers to making a function unusable, e.g. if you want to ban the use of dynamic allocation in a program you could "poison" the malloc function so it can't be used. 'Poisoning' an identifier means that any reference to the identifier after the 'poisoning' is a hard compiler error

For example (See live demo here)

#include <iostream>
#include <cstdlib>
#pragma GCC poison malloc
int main()
{
    int* p=(int*)malloc(sizeof(int));  // compiler error use of poisoned function malloc
    *p=3;
    std::cout<<*p<<'\n';
    free(p);
}

I found this technique very useful to prevent misuse of reserved words in C++.

For example:

#include "test.h"            // contains definition of some class T
#pragma GCC poison private
#define private public      // oops compiler error use of poisoned identifier private in macro
int main()
{
        // Instantiate T & use it members
}

This can also be used in C to prevent the use of C++ keywords because C++ has many keywords than C & it is perfectly valid to use C++ specific keywords as an identifier in C.

For example (See live demo here)

#include <stdio.h>
#pragma GCC poison new
int main(void)
{
     int new=5;     // oops compiler error use of poisoned identifer new.
     printf("%d",new);
}

But to use this poisoning we need to use the pragma directive which is implementation defined. Fortunately the GCC pragma reconginized by clang & also works nicely. But which pragma is needed If I 've VC++ compiler (Microsoft Visual studio). How to do this in VC++ compiler?

回答1:

MSVC++ has two ways to do this. To get the GCC version you'd use #pragma deprecated. That produces warning C4995, you can turn that into an error with /WX.

That however poisons any identifier with the name you specified, it isn't selective enough to prevent warnings on C++ members that happen to have the same identifier name. You couldn't use it to deprecate a specific function overload for example. Solved by the second way, __declspec(deprecated).

In general you'd prefer the latter to avoid accidental matches. But do beware that it has a chicken-and-egg problem, you can only deprecate a function that the compiler knows about. Forcing you to, say, #include a header that you don't want to use at all.