views:

339

answers:

8

I'm trying to think of a method demonstrating a kind of memory error using Arrays and C++, that is hard to detect. The purpose is to motivate the usage of STL vector<> in combination with iterators.

Edit: The accepted answer is the answer i used to explain the advantages / disadvantages. I also used: this

+7  A: 

Improperly pairing new/delete and new[]/delete[].

For example, using:

int *array = new int[5];
delete array;

instead of:

int *array = new int[5];
delete [] array;

And while the c++ standard doesn't allow for it, some compilers support stack allocating an array:

int stack_allocated_buffer[size_at_runtime];

This could be the unintended side effect of scoping rules (e.g constant shadowed by a member variable)... and it works until someone passes 'size_at_runtime' too large and blows out the stack. Then lame errors ensue.

Stephen
C++ does not support VLAs.
avakar
@avakar: C++ may not have them, but some compilers (such as gcc) offer them as an extensiosn.
Bill
@Stephen: Working on a certain compiler implies very little about the compliance of a bit of code. VLA's are C99 only, not C++. +1 for the first part, -1 for the second part, from me. @Bill: The question isn't about a particular compilers implementation of C++, it's about C++.
GMan
@GMan, unfortunately bugs don't check for standard compliance. And a few years ago I found out that this is a very real bug :( at least on g++.
Stephen
@Bill: we missed the part of the question that said "cross platform bugs". :)
Stephen
@all: edited the language in the answer to reflect standard conformance. Thanks for the feedback. To those who think this doesn't answer the question... the question is about real bugs being avoided... not standard compliance, not best practices and not cross platform code. I've been bitten, so I think it's valid. :)
Stephen
I think "C++ bugs" fall under errors you can make with the C++ language. Not bugs under some other language.
GMan
@GMan: fair enough. I'll go tell the developers of the C++ compilers that support VLA that they're compiling some other language.
Stephen
@Stephen: Well they are. That's why their called *extensions*. It's no longer compliant C++ if such code compiles. The definition of an array requires that the size be a constant-expression. If not, the program is not well-formed and the compiler shall emit a diagnostic. It's pretty simple; C++ is defined by the standard alone, no implementation defines what is C++ or not.
GMan
+6  A: 

A memory leak? IMO, vector in combination with iterators doesn't particularly protect you from errors, such as going out of bounds or generally using an invalidated iterator (unless you have VC++ with iterator debugging); rather it is convenient because it implements a dynamically resizable array for you and takes care of memory management (NB! helps make your code more exception-safe).

void foo(const char* zzz)
{
    int* arr = new int[size];
    std::string s = zzz;
    //...
    delete[] arr;
}

Above can leak if an exception occurs (e.g when creating the string). Not with a vector.

Vector also makes it easier to reason about code because of its value semantics.

int* arr = new int[size];
int* second_ref = arr;
//...
delete [] arr; 
arr = 0; //play it safe :)

//...
second_ref[x] = y;
//...
delete [] second_ref;

But perhaps a vector doesn't automatically satisfy 100% of dynamic array use cases. (For example, there's also boost::shared_array and the to-be std::unique_ptr<T[]>)

UncleBens
VC++ isn't the only C++ library with iterator debugging. STLPort has it too, and libstdc++ (the GNU C++ library) has it when you compile with `-D_GLIBCXX_DEBUG`.
Ken Bloom
@Ken: Thanks for informing me. (Personally I don't think of safety when I choose vector, I choose it because it is just does things for me.)
UncleBens
+2  A: 

Why don't you motivate it based on the algorithms that the STL provides?

Ken Bloom
Also a good point ... i'm going to consider this. Thanks :)
macs
STL provides all the same algorithms for arrays too. - But yes, the greatest motivator should be that vector *does things for you*, things which you would otherwise code up yourself (and unless you know C++ well, won't just know how to implement as efficiently, such as resizing).
UncleBens
Except that all (or at least almost all) STL algorithms that will work on a `std::vector` will also work on a raw array using pointers into the array as iterators.
Tyler McHenry
@Tyler: I think *all* because they belong to the same iterator category.
UncleBens
@Tyler: to do that, you have to think about raw arrays as iterators. Usually in C, you pass in an array `a` and a size `n`. In the STL, you pass in a pointer to the start element (which is the array pointer `a`), and a one-past-the-end pointer (`a+n`). From there, it's a small step to `vector<something>` with its `begin()` and `end()` menbers, and you can motivate it further by the fact that it's now interchangeable (at least mostly) with `std::list` and `std::deque`.
Ken Bloom
+3  A: 

One obvious:

for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
    destination_array[i] = whatever(i);

versus

for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
    destination_vector.push_back(whatever(i));

pointing out that you know the second works, but whether the first works depends on how destination_array was defined.

David Thornley
+4  A: 

I think the utility of std::vector really shows when you need dynamic arrays.

Make one example using std::vector. Then one example using an array to realloc. I think it speaks for itself.

Nikko
+3  A: 
void Fn()
{
    int *p = new int[256];
    if ( p != NULL )
    {
        if ( !InitIntArray( p, 256 ) )
        {
              // Log error
              return;
        }
        delete[] p;
    }
}

You wouldn't BELIEVE how often I see that. A classic example of where any form of RAII is useful ...

Goz
I would BELIEVE.
Joshua
+3  A: 

I would think the basic simplicity of using vectors instead of dynamic arrays is already convincing.

  1. You don't have to remember to delete your memory...which is not so simple since attempts to delete it might be bypassed by exceptions and whatnot.
  2. If you want to do dynamic arrays yourself, the safest way to do it in C++ is to wrap them in a class and use RAII. But vectors do that for you. That's kind of the point, actually.
  3. Resizing is done for you.
  4. If you need to support arbitrary types, you don't have to do any extra work.
  5. A lot of algorithms are provided which are designed to handle containers, both included and by other users.
  6. You can still use functions that need arrays by passing the vector's underlying array if necessary; The memory is guaranteed to be contiguous by the standard, except with vector<bool> (google says as of 2003, see 23.2.4./1 of the spec).
  7. Using an array yourself is probably bad practice in general, since you will be re-inventing the wheel...and your implementation will almost definitely be much worse than the existing one...and harder for other people to use, since they know about vector but not your weird thing.

With a dynamic array, you need to keep track of the size yourself, grow it when you want to insert new elements, delete it when it is no longer needed...this is extra work. Oh, and a warning: vector<bool> is a dirty rotten hack and a classic example of premature optimization.

Brian
+1 for the answer, but keep in mind that 'vector' is all lowercase; FTFY.
Matteo Italia
A: 

In raw array, operator[] (if I may call so) is susceptible to index-out-of-bound problem. With vector it is not (There is at least a run time exception).

Sorry, I did not read the question carefully enough. index-out-of-bound is a problem, but not a memory error.

ArunSaha
operator[] in vector **doesn't** check bounds; the check is instead performed by the *at* method.
Matteo Italia