0

My problem is this - I tried to make a Heap checker to be used in testing and for this

a) overload standard global new/delete operators so that they let my custom class know about each alloc and delete

b) add custom new operators that have a signature like

void* operator new(size_t size, const char* filename, const char* function, int line)

c) make a macro that replaces standard new calls with my new calls and the given file, func & line

#define new new(__FILE__, __FUNCTION__, __LINE__)
  • this works well, except for cases where somebody uses a custom new in a class or operator new() directly - that means that I can only define this macro after loading in standard C++ libs (functional, algo, string...), as they are heavy on doing that stuff

d) so we came up with the brilliant idea of using var-arg macro which would solve these problems

#define new(...) new(__VA_ARGS__, __FILE__, __FUNCTION__, __LINE__)
  • this works well for all the problematic cases in the last point, as any parameters passed to either new (someargs) or operator new(size_t, someargs) gets replaced by the var-arg macro and sent into my custom new operators

  • But it doesn't work for the most usual case of just calling:

int* ptr = new int;

  • because the new call doesn't have parentheses, therefore it's not expanded as a function macro

Which brings me to the question mentioned in the title : Is there any way to do this with macros so that one would be able to replace the same character sequence in original code no matter whether it's called without a parameter list or with one?

The desired result in this case would be:

new without parentheses after it - new -> new(__file__, __func__, __line__)

new with parentheses after it - new(args) -> new(args, __file__, __func__, __line__)

I realize that this is an obvious case of trying to redefine the same macro, so it shouldn't be possible. I'm looking for some preprocessor magic that would let me get around that.

Disclaimer : I know it's ugly and we actually settled on the solution in c) with simply ignoring the standard library news. But as I did spend some time researching the possibility I'd be interested if anyone has a potential way to do this.

Cheerios!

___EDIT___ Please don't concentrate on what I'm trying to accomplish but only on the question in the title. The Heap Checker itself can be implemented in a variety of standard-compliant ways and this is not one of them :) It's more of my curiosity as to how much it's possible to bend the language with the preprocessor.

The question stands - can I use some preprocessor commands to achieve a different behaviour for the same sequence with and without parentheses after it (that is, something that works just as if I had both a function-like and object-like macro of the same name)

Thanks for any and all answers :)

tommybazar
  • 63
  • 1
  • 6
  • 8
    Redefining a keyword(`new`) with a macro is undefined behavior. – NathanOliver Oct 13 '17 at 13:52
  • Any reason why you can't just override/overload the function? Macros are usually evil anyhow. – UKMonkey Oct 13 '17 at 14:12
  • @NathanOliver can you please provide reference to the C++ standard? – roalz Oct 13 '17 at 14:17
  • See also: https://stackoverflow.com/q/9109377/2785528 – 2785528 Oct 13 '17 at 14:20
  • I want to see where in the code I allocated a thing that I forgot to deallocate. Didn't find any better way then `__LINE__, __FILE__` and as these are preprocessor macros, I needed to pass them to my new in that step. And the fact that I _am_ breaking some standards was pretty obvious to me from how ugly it seems, it's not going into any production code, that's for sure :) Let's just say that even the one overriding new for std libs _did_ work (as I'm practically just adding parameters to the new operator in the macro that I store and call the regular `new`) – tommybazar Oct 13 '17 at 14:24
  • 1
    @tommybazar Is valgrind an option? `valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all` will give you a pretty detailed overview of your allocations if you compile your program with debug symbols – Ctx Oct 13 '17 at 14:30
  • @roalz SO Q&A that does: https://stackoverflow.com/questions/9109377/is-it-legal-to-redefine-a-c-keyword – NathanOliver Oct 13 '17 at 14:39
  • Valgrind is of course a friend of mine, but this would in the end run on an embedded chip, where I don't have access to it. – tommybazar Oct 13 '17 at 14:42
  • Someone asked for a citation why this is UB: https://stackoverflow.com/questions/9109377/is-it-legal-to-redefine-a-c-keyword – Kenny Ostrom Oct 13 '17 at 15:35

1 Answers1

0

No, you can't. See §16.3p2 [cpp.replace] of the C++ standard (similar wording found in other versions and in the equivalent section of the C standard; nothing has changed) (emphasis mine):

An identifier currently defined as an object-like macro (see below) may be redefined by another #define preprocessing directive provided that the second definition is an object-like macro definition and the two replacement lists are identical, otherwise the program is ill-formed. Likewise, an identifier currently defined as a function-like macro (see below) may be redefined by another #define preprocessing directive provided that the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical, otherwise the program is ill-formed.

In other words, a macro identifier is either object-like or function-like, but the same identifier cannot be used for both.

rici
  • 234,347
  • 28
  • 237
  • 341