Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'd like to know if it's possible to detect the delete error commented below at compile time? Especially, I'd like to hear about g++ compiler.

ClassTypeA *abc_ptr = new ClassTypeA[100];  
abc_ptr[10].data_ = 1;  
delete abc_ptr; // error, should be delete []  

Thanks in advance!

share|improve this question
3  
You should not be calling delete manually anyway. –  Loki Astari Feb 13 '13 at 18:16
8  
@LokiAstari Did you actually think that comment was helpful? –  James Feb 13 '13 at 20:36
1  
@James: Yes. The key is "manually". –  Loki Astari Feb 14 '13 at 0:39

4 Answers 4

up vote 4 down vote accepted

In general, the compiler can't detect such errors. Example: Suppose the constructor for some class allocates some data member using new TypeName[], but the destructor erroneously uses delete instead of delete[]. If the constructor and destructor are defined in separate compilation units, how is the compiler to know when compiling the file that defines the destructor that the usage is inconsistent with that in the separately compiled file that defines the constructor?

With regard to the GNU compilers, it doesn't. As noted above, it can't do so in the general case. A compiler doesn't have to detect such mismatched new/delete errors because this is undefined behavior. UB is the compiler vendor's "get out of jail free" card.

Tools such as valgrind can and do detect these kinds of new/delete mismatches, but do so at runtime. There might be a static analysis tool that looks at all of the source files that will eventually be compiled to form an executable, but I don't of any such static analysis tool that detect this kind of error.

share|improve this answer
    
I've used a static analysis tool called Parasoft that definitely has a rule for this specific scenario. It does run on all of the files in a particular project (if it's been configured correctly). That being said, I'm not certain how well it handles scenarios such as Pete Kirkham's comment on Kilian Foth's answer. –  Velociraptors Feb 15 '13 at 1:38

You can use the appropriate RAII classes to delete. This is the only safe way of doing it, and this error is only one of the very, very many you will encounter calling delete yourself.

Always use classes to manage dynamic lifetime resources, and the type system will enforce correct resource destruction.

Edit: "What if you're auditing the code and can't change it?" You're fucked.

share|improve this answer
18  
-1 because this does not actually answer the question. –  Mason Wheeler Feb 13 '13 at 14:43
2  
The only way to detect the mismatch is to use the type system, which involves using RAII classes. –  DeadMG Feb 13 '13 at 14:45
8  
...that makes even less sense. What does the use of RAII classes--a runtime mechanism--have to do with static type system information that the compiler knows about at compile-time? –  Mason Wheeler Feb 13 '13 at 14:54
5  
@MasonWheeler see boost::shared_ptr and boost::shared_array as examples. Destroying the shared_ptr deletes the object, destroying the shared_array delete[]s the array. You can't assign a shared_array to a shared_ptr, so - as long as you don't construct a shared_ptr with an array in the first place - the type system prevents the wrong delete being used. –  Pete Kirkham Feb 13 '13 at 14:59
2  
Normally, an answer like this is more obnoxious than helpful. However, in this case, it is actually true. He's looking for compiler enforcement of a common error, and using RAII properly prevents this style of error, thereby giving him exactly what he wants. +1 –  Stargazer712 Feb 13 '13 at 16:30

This particular error - yes. This kind of error generally: unfortunately, no! That would involve predicting the flow of execution without actually executing it, and that isn't possible for arbitrary programs. (That's why most compilers don't even try to detect simple cases like your example.)

Therefore DeadMG's answer is the appropriate one: don't try to get it right by paying attention - human attention is fallible. Use the language-provided means and let the computer pay attention.

share|improve this answer
    
How does this require predicting the flow of execution? This looks like purely static, compile-time knowledge to me; the compiler's type system knows what's an array and what isn't. –  Mason Wheeler Feb 13 '13 at 14:48
    
Even in the presence of casts? Sorry, if I got that wrong I'll delete the answer. –  Kilian Foth Feb 13 '13 at 14:55
12  
@MasonWheeler the static type of abc_ptr is ClassTypeA* so you can insert a line between the new and the delete if ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA; Nothing in the static type system is showing whether abc_ptr points to an array or a dynamic object or part way into another object or array. –  Pete Kirkham Feb 13 '13 at 14:56
    
...oh, right. I'm so used to working with languages with real array types that I keep forgetting how screwed up it is over in C-land. :( –  Mason Wheeler Feb 13 '13 at 16:20
1  
@Pete Kirkham, @Mason Wheeler: But still, the runtime should see how many objects are stored at the address pointed to by abc_ptr, otherwise how could it be able to deallocate the right amount of memory? So the runtime knows how many objects must be deallocated. –  Giorgio Feb 14 '13 at 10:09

The trivial case which you show can be detected at compile time, because the instantiation and destruction of the object are in the same scope. In general, the deletion is no in the same scope, or even the same source file, as the instantiation. And a C++ pointer's type does not carry information about whether it references a single object of its type or an array, let alone the allocation scheme. So it is not possible to diagnose this at compile time in general.

Why not diagnose the special cases that are possible?

In C++ there are already tools for dealing with leakage of dynamic resources that are tied to scopes, namely smart pointers and higher level arrays (std::vector).

Even if you use the correct delete flavor, your code is still not exception safe. If the code between the new[] and delete[] terminates by a dynamic exit, the deletion never executes.

As far as run-time detection goes, the Valgrind tool does a good job of detecting this at run-time. Watch:

==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781==    at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048498: main (in /home/kaz/test/a.out)
==26781==  Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048488: main (in /home/kaz/test/a.out)

Of course, Valgrind doesn't run on all platforms, and it's not always practical or possible to reproduce all run-time situations under the tool.

share|improve this answer
    
you say that this trivial case can be detected at compile time. Could you please tell me what compilation command you use to achieve that? –  SebGR Feb 13 '13 at 17:12
    
"can be detected at compile time" here means that it is easy to implement in a compiler, not that g++ has it. A compiler has the whole lifetime of the identifier in its grasp when processing that scope, and can propagate the allocation info as as semantic attribute tied to the syntax. –  Kaz Feb 13 '13 at 17:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.