Reason why not to have a DELETE macro for C++
Personally I prefer the following
template< class T > void SafeDelete( T*& pVal )
{
delete pVal;
pVal = NULL;
}
template< class T > void SafeDeleteArray( T*& pVal )
{
delete[] pVal;
pVal = NULL;
}
They compile down to EXACTLY the same code in the end.
There may be some odd way you can break the #define system but, personally (And this is probably going to get me groaned ;) I don't think its much of a problem.
C++ Stop Preprocessor Macro Expansion
What you're trying to do is not possible, as Michael Karcher's answer states: #define delete
already makes the program ill-formed, and expanding an object-like macro (outside its own expansion) cannot be avoided.
However, for your particular use case detailed in the question, a workaround is possible. You could put your #define delete
into a header file (let's call it debug_delete.hxx
), like this:
#ifdef delete
# undef delete
#endif
#define delete MyCustomDelete(__FILE__, __LINE__), delete
Then, create another header file (let's call it normal_delete.hxx
):
#ifdef delete
# undef delete
#endif
Note in particular that there is no mechanism in these headers to prevent multiple inclusion; in fact, we want them includable an arbitrary number of times.
Then, wrap code which must use = delete;
in appropriate #include
directives:
class A {
#include "normal_delete.hxx"
A() = delete;
#include "debug_delete.hxx"
~A() { delete p; }
};
(Yes, it's ugly, but what you're doing is sort of ugly in the first place, so ugly code may be required to make it work).
When should you use macros instead of inline functions?
There's a couple of strictly evil things about macros.
They're text processing, and aren't scoped. If you #define foo 1
, then any subsequent use of foo
as an identifier will fail. This can lead to odd compilation errors and hard-to-find runtime bugs.
They don't take arguments in the normal sense. You can write a function that will take two int
values and return the maximum, because the arguments will be evaluated once and the values used thereafter. You can't write a macro to do that, because it will evaluate at least one argument twice, and fail with something like max(x++, --y)
.
There's also common pitfalls. It's hard to get multiple statements right in them, and they require a lot of possibly superfluous parentheses.
In your case, you need parentheses:
#define radian2degree(a) (a * 57.295779513082)
needs to be
#define radian2degree(a) ((a) * 57.295779513082)
and you're still stepping on anybody who writes a function radian2degree
in some inner scope, confident that that definition will work in its own scope.
Why doesn't delete set the pointer to NULL?
Stroustrup himself answers. An excerpt:
C++ explicitly allows an
implementation of delete to zero out
an lvalue operand, and I had hoped
that implementations would do that,
but that idea doesn't seem to have
become popular with implementers.
But the main issue he raises is that delete's argument need not be an lvalue.
Is the pointer guaranteed to preserve its value after `delete` in C++?
No, it's not guaranteed and an implementation may legitimately assign zero to an lvalue operand to delete
.
Bjarne Stroustrup had hoped that implementations would choose to do this, but not many do.
http://www.stroustrup.com/bs_faq2.html#delete-zero
Which version of safe_delete is better?
Clearly the function, for a simple reason. The macro evaluates its argument multiple times. This can have evil side effects. Also the function can be scoped. Nothing better than that :)
NULL check before deleting an object with an overloaded delete
No, don't check for null. The standard says that delete (T*)0;
is valid. It will just complicate your code for no benefits. If operator delete
is overloaded it's better to check for null in the implementation of the operator. Just saves code lines and bugs.
EDIT: This answer was accepted and upvoted, yet, in my opinion, it was not very informative. There is one missing piece in all answers here, and, for conscience sake, let me add this last piece here.
The standard actually says in [basic.stc.dynamic], at least since C++03:
Any allocation and/or deallocation functions defined in a C++ program, including the default versions in the library, shall conform to the semantics specified in 3.7.4.1 and 3.7.4.2.
Where the referenced sections, as well as some other places in the standard listed in other answers, say that the semantics of passing a null pointer are a no-op.
How to replace delete and delete []
This isn't a good idea. Macros are not the proper tool for the job. Aside from the fact that it probably isn't possible, it will be confusing to anyone maintaining your code. There are several superior alternatives.
If you have C++11, you should prefer to use smart pointers such as std::unique_ptr
and std::shared_ptr
whenever possible. MatthiasB also makes a valid point that you should opt to take advantage of the standard library and use std::vector
instead of dynamically allocated arrays.
Otherwise, you can take advantage of tools like valgrind and LLVM's AddressSanitizer. It's available in Clang and has been ported to GCC 4.9. To use it, specify -fsanitize=address
at the command line.
If you insist on textual replacement, a manual search-and-replace in your favorite IDE might do the trick. I wouldn't recommend it though.
A discussion in Is it good practice to NULL a pointer after deleting it? reveals that this practice is indicative of possible design problems in your program. For example, jalf's answer:
Setting pointers to NULL after you've deleted what it pointed to
certainly can't hurt, but it's often a bit of a band-aid over a more
fundamental problem: Why are you using a pointer in the first place? I
can see two typical reasons:
- You simply wanted something allocated on the heap. In which case wrapping it in a RAII object would have been much safer and cleaner.
End the RAII object's scope when you no longer need the object. That's
howstd::vector
works, and it solves the problem of accidentally
leaving pointers to deallocated memory around. There are no pointers.- Or perhaps you wanted some complex shared ownership semantics. The pointer returned from
new
might not be the same as the one that
delete
is called on. Multiple objects may have used the object
simultaneously in the meantime. In that case, a shared pointer or
something similar would have been preferable.
My rule of thumb is that if you leave pointers around in user code,
you're Doing It Wrong. The pointer shouldn't be there to point to
garbage in the first place. Why isn't there an object taking
responsibility for ensuring its validity? Why doesn't its scope end
when the pointed-to object does?
Related Topics
Boost::Flat_Map and Its Performance Compared to Map and Unordered_Map
How to Create a Simple Qt Console Application in C++
Has Anyone Ever Had a Use for the _Counter_ Pre-Processor MACro
How to Find All the Functions Exposed by a Dll
How to Append a Char to a Std::String
Why How to Access Private Variables in the Copy Constructor
Linux Perf: How to Interpret and Find Hotspots
Converting from Signed Char to Unsigned Char and Back Again
Void_T "Can Implement Concepts"
Why Does C++ Not Let Baseclasses Implement a Derived Class' Inherited Interface
Unoptimized Clang++ Code Generates Unneeded "Movl $0, -4(%Rbp)" in a Trivial Main()
Why Do Un-Named C++ Objects Destruct Before the Scope Block Ends