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.
Printable View
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.