If a create a pointer with new[] (not just new) must I delete it with delete[] (not just delete).
Printable View
If a create a pointer with new[] (not just new) must I delete it with delete[] (not just delete).
Yes, you must.
delete would just free the memory of the first element
Undefined behaviour. Speculating about what you said, I think it would free all memory, but would call only destructor for first element (though it may probably be smart enough to compare size of class and allocated memory and act indifferent of what was called, but most likely this functionality wouln't be included).Quote:
Originally Posted by Padan
with VC++ 6.0, calling delete when delete[] is required only calls the constructure of the first class then produces an exception. For simple (elementary) data types, such as int, there is no problem, but its not a good idea to use delete then either.
It's not a good idea because it might not produce the correct behaviour on a different compiler. That is what is meant by "undefined" behaviour.
It's never a good idea to call delete when delete[] is required but since the pointer points to the first element of the array the first element should always be freed. Access to the other elements is not possible afterwards.
No, it shouldn't always be freed. It's undefined behaviour.Quote:
Originally Posted by Padan
Not only in this case, you shouldn't use it in the vice versa case, i.e, using delete [] when delete is required. From Item 16: Effective C++, 3rd edition.
Quote:
When you use delete on a pointer, the only way for delete to know whether the array size information is there is for you to tell it. If you use breackets in your use of delete, delete assumes an array is pointed to. Otherwise, it assumes that a single object is pointed to:
What would happen if you use the "[]" form on stringPtr1? The result is undefined, but it's unlikely to be pretty. Assuming the layout above, delete would read some memory and interpret what it read as an array size, then start invoking that many destrucutors, oblivious to the fact that the memory it's working on not only isn't in the array, it's also probably not holding objects of the type it's busy destructing.Code:std::string * stringPtr1 = new std::string;
std::string * stringPtr2 = new std::string[100];
What would hapeen if you didn't use "[]" form on stringPtr2? Well, that's undefined too, but you can see how it would lead to too few destrucotors being called. Furthermore, it's undefined (and sometimes harmful) for built-in types like ints, too, even though such types lack destructors.
The rule is simple: if you use[] in a new expression, you use must [] in the correspoinding delete expression. If you don't use [] in a new expression, don't use [] in the matching delete expression.
Why not using std::vector?Quote:
Originally Posted by RatmilT
here is a good example from a good book.Quote:
Originally Posted by RatmilT
In C++, you can create arrays of objects on the stack or on the heap with equal ease, and (of course) the constructor is called for each object in the array
When creating arrays of objects on the heap using new, there’s something else you must do. An example of such an array is
When creating arrays of objects on the heap using new, there’s something else you must do. An example of such an array is
This allocates enough storage on the heap for 100 MyType objects and calls the constructor for each one. Now, however, you simply have a MyType*, which is exactly the same as you’d get if you saidCode:MyType* fp = new MyType[100];
to create a single object. Because you wrote the code, you know that fp is actually the starting address of an array, so it makes sense to select array elements using an expression like fp[3]. But what happens when you destroy the array? The statementsCode:MyType* fp2 = new MyType;
look exactly the same, and their effect will be the same. The destructor will be called for the MyType object pointed to by the given address, and then the storage will be released. For fp2 this is fine, but for fp this means that the other 99 destructor calls won’t be made. The proper amount of storage will still be released, however, because it is allocated in one big chunk, and the size of the whole chunk is stashed somewhere by the allocation routine.Code:
delete fp2; // OK
delete fp; // Not the desired effect
The solution requires you to give the compiler the information that this is actually the starting address of an array. This is accomplished with the following syntax:
The empty brackets tell the compiler to generate code that fetches the number of objects in the array, stored somewhere when the array is created, and calls the destructor for that many array objects.Code:delete []fp;
See this ;)
std::vector can be used in many places instead of new[], but not all places.Quote:
Originally Posted by NoHero
For example, you cannot assume that std::vector contained objects are contiguous in the memory.
So ((&v[0])+index) is not supposed to point to a valid element.
So, you cannot use std::vector (even if it works with most (if not all) implementations of std::vector) to pass data to a third-party library function, or to some C code, or to some Win32 API.
Also, you cannot assume that two different C++ compilers have the same implementation of std::vector, so exported functions (in binary libraries) must not use std::vector for their functions arguments/return value.
vectors works fine when used inside a project, by using iterators instead of pointers everywhere.
So, depending on the project, std::vector may, or may not be usable.
I am not sure, but maybe in next versions of the STL, std::vector will be assumed to address contiguous memory.
This is Incorrect. It will point to a valid element provided there is one.Quote:
Originally Posted by SuperKoko
Even if I need to pass an array down to WinAPI I use a self written generic container using std::vector() as underlying structure, which can build such an array for me. And since std::vector() is ANSI standard I assume that std::vector() is part of every C++ implementation/compiler.Quote:
Originally Posted by SuperKoko
I think that std::vector does enforce a contiguous array. The other part of your statement is true though - it is not guaranteed to be portable across libraries.
I searched on the net.Quote:
Originally Posted by NMTop40
You are right, it was originally a defect of the ISO standard, there has been a defect report, and now there is a Corrigenda saying that arrays must be contiguous.
To see the original defect report go to:Quote:
TC - (Technical Corrigenda) - The full WG21 committee has voted to accept the Defect Report's Proposed Resolution as a Technical Corrigenda. Action on this issue is thus complete and no further action is possible under ISO rules.
http://www.open-std.org/jtc1/sc22/wg...g-defects.html
and search for "69. Must elements of a vector be contiguous?" on the page.
You can also follow this interesting link:
http://bdn.borland.com/article/0,1410,10286,00.html
This "good" example from a "good" book is wrong. As was stated before, allocating objects with new[] and deleting with regular delete is undefined behavior. This means that anything could happen; it could destroy one element, it could destroy all 100 elements, it could format your hard drive, anything. The standard makes absolutely no statement as to what happens in this case, so you cannot rely upon any behavior that a particular compiler would implement. The quote you gave is just an author's assumption of what would happen and is not backed up by the standard.Quote:
Originally Posted by humptydumpty
I guess the author must have been talking about some specific platform/environment. In that case he would be correct but yes this is going to be implementation specific.Quote:
Originally Posted by Bob Davis
:D ... Don't be so pessimistic.Quote:
Originally Posted by Bob Davis
Yes, and even if some C++ implementation clearly states what happens when delete[] is called on a block allocated with new, or when delete is called on a block allocated with new[], you cannot even rely on this behavior, because it is also user-dependent.Quote:
Originally Posted by Bob Davis
That is, since global versions of operator new, new[], delete and delete[] can be overloaded.
Not only, destructors can be called totally incorrectly, but the memory deallocation can behaves totally impredictablely, even if the compiler states how the memory is dealocated.
Moreover, generally, compilers don't say how default delete and delete[] behaves, and even if for some versions of some compilers, delete seems to work with POD types allocated with delete[], the next version of the compiler can totally change this behaviour.
Moreover, it is so easy to use delete[] when needed that i don't see any interest to use delete were you must use delete[] (of course, this error is always due to a typo or mistake).
Thanks to all.
In addition to what SuperKoKo said, there's a common myth among Visual C++ programmers that it's OK to use delete instead of delete [] to release arrays built-in types. For example,
This is totally wrong. The C++ standard specifically says that using delete to release dynamically allocated arrays of any type—including built-in types—yields undefined behavior. The fact that on some platforms apps that use delete instead of delete [] don't crash can be attributed to sheer luck: Visual C++, for example, implements both delete and delete [] for built-in types by calling free(). However, there is no guarantee that future releases of Visual C++ will adhere to this convention. Furthermore, there's no guarantees that this will work with other compilers. To conclude, using delete instead of delete[] and vice versa is a very bad programming habit that should be avoided.Code:int *p = new int[10];
delete p; // very bad; should be: delete[] p
Right. If you use new, use delete. If you use new[], use delete[]. If you don't like any of these use garbage collector. In 99/100 situations using a good garbage collector is the best solution. :)
It's completely different architecture with its advantages and (alas...) disadvantages.
Why different architecture? I didn't mean C++.NET and other VM based garbage colletors. I meant pure C++ native collectors like BDW/RTGC/SMEIL. In my opinion there are more advantages than disadvantages, because most disadvantages are easily "workaroundable".
One of disadvantages which isn't "workaroundable" is that when you use GC it's allowed for object to be collected by GC. And it changes architecture, "spoiling" C++ style.
As long as the object is accessible, it won't get collected.
Besides you can tell GC not to touch some objects. And you can still deallocate objects in a usual way (I'm not sure if BDW allows this, but smart pointer implementations surely do).
The biggest problem I have with GC is that it screws up RAII. There are times (many, many of them) when you want to know exactly when a destructor's going to be called. In fact, intelligent use of RAII completely obviates the need for garbage collection.
(RAII = Resource Acquisition Is Initialisation: acquire a resource in the constructor, release it in the destructor. Useful for memory management, locks and any other resource that has to be properly managed.)
For easy and safe memory management, i like reference counters and smart pointers.
It solves 99% of the memory management problems where garbage collection could be used, and let the feature be well individualised.
And it is not slow (good GC are also known to be fast).
When you absolutely want to optimize a code, you can use weak references when needed.
The only thing that GC can do, and reference counting cannot do correctly, is the usage of recursives structures.
When i say recursive, it means that one object can point to another object which contains a pointer to the first object, and both objects are reference counted, and the objects are never explicitly detached one from the other (by assigning one pointer to NULL).
For example, a tree is not a recursive structure.
But those structures are generally containers or data structures already implemented by the STL, or an other library.
And if this data structure is not already implemented, you can implement it, being very careful, because generally it only represents a very small part of the project's code.
Moreover, what i like with reference counting, is the possibility to implement copy-on-write objects like some good implementations of std::string does.
(Ok now the discussion may get a bit off-topic when we are talking GCs but here goes...)Quote:
Originally Posted by SuperKoko
Actually another thing that GC generally does and that are difficult with reference counted smart pointer is defragmenting the heap. The heap, as well as a disk, may become cluttered with many small pockets/holes of memory that doesn't quite fit an object but still takes memory. GCs usually can defragment heaps and remove such pockets.
A place where GC doesn't quite deliver is when the GC is run by a another thread (most implementations is like that). But some resources may be thread-affine and must be deallocated by the same thread that allocates it. But since the GC thread only deallocates and never allocates it's can't deallocate such objects. Noteably such resources are windows handles which is why:
(C# code)
will leak resources even though C# has a garbage collector.Code:
Graphics l_g = m_label.CreateGraphics();
What you have to do in such case is this:
Which basically translates to:Code:
using( Graphics l_g = m_label.CreateGraphics() )
{
}
Which is more or less the same as in C++ doing:Code:Graphics l_g;
try
{
l_g = m_label.CreateGraphics();
}
finally
{
l_g.Dispose();
}
The try...finally pattern is also common in java when for instance writing to log-files and you want to be sure that you close the log-file whenever you leave the function scope (so that next time a thread calls a log function it can open and write to the log-file). If you leave it to the GC you don't know when it will released and thus you may or may not get sharing violations when a thread calls the log function.Code:A* l_a = new A();
// ...
delete l_a;
In C++ we don't have try...finally but we have deterministic destructors and stack-based objects which turns out to be very useful for life-time management. So instead of writing new/delete you should use some kind of smart pointer:
(For instance)
If you adopt RAII techniques _always_ you will find that life-time management really is a minor issue mostly when programming C++. Difficult situations like circular references may occur but they can usually be solved by using weak-references in strategic places or object pools.Code:std::auto_ptr<A> const l_a(new A()); // makes sure the destructor is called always
The biggest problem with RAII IMO is that in C++ a very strong recommendation is to never let destructors throw. However, there are no good ways of reporting a failure from the destructor that the surrounding code really should need to know about.
For instance: You have transaction RAII object that commits or rollbacks in the destructor depending on a flag. Let's say you do a couple of small operations in sequence and commit each one. In the middle of the operations the network connection to the db dies. When committing the destructor detects it. What should it do?
o Throwing from destructors generally gives experienced C++ programmers a bad taste in the mouth.
o Not throwing is not good either since the surrounding code should be notified of this failure.
o Setting a global flag doesn't really sound like an attractive option either.
o Setting a flag on the object isn't an option since it's about to be destroyed and you can't stop a destructor from happening.
AFAIK there isn't a good answer to this in C++ which is unfortunate.
There are no simple answers or rule of thumbs in this post but I hope it was of interest to somebody.
Destructors should not do anything though except to free up resources that have been allocated. This includes unlocking mutexes. If pthread_mutex_unlock() returns an error ignore it.
If you really have to give a warning, ensure that giving a warning is an exception-safe action.
A destructor on a database transaction should ALWAYS rollback. It is against the nature of a destructor to commit it.
You may decide to have a wrapper class that, in one step, will commit the transaction then delete the transaction object. But that would not be a destructor.
I don' tknow why, when you are talking about smart pointers, you mean reference counting smart pointers, don't you? I know, they are useful, but actually home made, naive implementations are much slower than GCs[1] and as stated above, they have problems with reference cycles. Some GCs also use smart pointers, so if you don't like GC in some part of your code, you just use RAII with new/delete and there is no problem.
1. RAII is nice pattern, especially when you have objects allocated on the stack. But with heap allocated ones I can see one problem: what happens if you forget to call delete (or an exception is raised)? You've got a difficult to debug resource leak. So you must be really careful.
2. And now, let's consider you have a GC. You define a method in the object that does what the destructor would do and name it e.g. "dispose". You also define a destructor, that checks if dispose() was called and if not, it issues a warning and calls it. Of course, you manually call dispose just before you don't need the object anymore, so that it is disposed as early as possible. This would work just as well as in point 1. with exception that if you forget to call dispose(), you WILL surely know it, and you've got a chance to debug, which object it was.
Of course this concerns only resources that must be disposed as early as possible. For other objects (majority[2]), if you have GC, you just don't need destructors.
[1] Hans Boehm "Memory Allocation Myths and Half-Truths" << It's really good. Read it :) This guy is a real expert.
[2] We work on a Java project that is now more than 400 classes large, and there are only a few classes that require deterministic destruction.
My largest gripe about garbage collectors is that they don't work well (i.e. they greatly complicate) real-time systems. You have to worry about how long collection will take, the priority of the GC thread if it runs in a seperate thread, etc.... GC has its place. But it doesn't belong everywhere.
Quote:
Originally Posted by marten_range
I was talking about using a GC in C++ application (not in a managed language such as C# or Java).Quote:
Originally Posted by marten_range
And GC cannot compact data if the data structures are not clearly defined, so with C++ GC are conservatives (that is, every DWORD in memory is considered as a pointer).
And it cannot compact.
And for thread safety reasons, the GC cannot collect garbage in another thread.
I don't doubt that a managed language can be fine.
In fact, in all my projects that used reference counting, it was explicit reference counting:
That is, some relatively big objects which needed some reference counting were derived from a class like that:
And i used AddRef at a few locations in my code, when a new strong reference was truly needed.Code:class TAutoObject
{
private:
DWORD cRefs;
TAutoObject(const TAutoObject &);
void operator=(const TAutoObject &);
public:
void AddRef() {++cRefs;}
void Release()
{
if (--cRefs==0) delete this;
}
protected:
TAutoObject():cRefs(1) {}
virtual ~TAutoObject() {}
};
Because my objects belonged only to one thread, AddRef/Release did not need to be thread safe.
The only thing that could really slow my application, is the fact that such reference-counted objects uses 4 bytes for each objects (generally my objects were using at least 12 other bytes).
So reference counting can be very fast, combined with a good memory allocation routine (VC++ uses a really slow malloc, but there are some other allocation routines available on internet).
A good GC can also be very fast.
I can't agree with statement that GCs are not suitable for real-time applications. It was right perhaps 10 years ago. Nowadays there are some real-time implementations for C++. I know at least 3: BDW in incremental mode, RTGC and my SMEIL.
It is also not true, that GC cannot run in a separate thread. Actually most of GCs for C++ do it this way. Another myth is that GC must stop users's threads for a time of collection. It depends only on the collection algorithm. There are algorithms that can run concurrently or can be stopped and resumed in the middle of the collection cycle. Modifications of pointer values while collecting garbage also don't spoil anything. Of course there is a little overhead if compared to traditional blocking collectors, but this overhead is usually less than a few percent.
A problem with reference counting is thread-safety. If you write a single-threaded implementation, probably it can be only little slower than best real-time GCs. You still have to copy additional pointer, increase, decrease counter and check a condition per every pointer assignment. In thread-safe reference counting is worse, because you need to do interlocked increment and decrement. These usually need calling system functions, and are slower even more (if you do it with mutexes, you can get hundreds times slower - so don't do it like that).
In SMEIL for example, the only overhead is copying additional 4B field and setting a flag, which takes not more than 20% of time for reference count update. And it is thread-safe.
Heap fragmentation myth is fortunately only a myth. Size of heap hardly ever exceeds 150% of required memory size in good, native allocators [1]. So using a heap that is twice as large as needed [2] right from the start to fight fragmentation in managed environments like C# or Java is a bad idea of saving memory. It is done to speed up the allocation process, not to save memory.
What is the most advantage of GCs C++ over GCs in Java/C# is that C++ applications produce much less garbage. Most of short living objects live on the stack, and don't slow down the collector.
[1] According to Boehm's measurements.
[2] At least half of the heap is never used in Java.
That is right, C++ uses less pointers to tiny objects, and it is probably the reason why conservative GC in C++ is not slower than GC in managed languages as said Boehm.Quote:
Originally Posted by pkolaczk
Interesting. I'll have to take a look at those 3 in case I do need them in the future.Quote:
Originally Posted by pkolaczk
However, if you take another look at my post, I said that using GC's are more complicated in a real-time environment, not that they couldn't be used. They complicate things, because (a) you're not sure how long a particular collection will take [a concern if you don't run the GC in a seperate thread] and (b) if you run the GC in a seperate thread, you have to think about the thread priority of the GC thread and how it relates to other thread's priorities. I've usually found it easier with the applications I've dealt with anyway, to avoid GC's altogether. But maybe the 3 GC's mentioned will help alleviate the issues I have.