1

I am creating a dynamic array inside a function. The code (posted below) runs without any problem. I am wondering if the way I have written is the right way to do it or if it will create problems in more complicated codes in the future. I am aware that the specific task my program (below) is trying to achieve is better effected with strings or vectors. But I created this artificial example to get my question across. however, if you strongly feel that dynamic arrays should be avoided, please feel free to share your opinion and the reasoning for it.

Result of my prior research: I was unable to find a coherent discussion on legality and morality of creating dynamic arrays using new [] and later deleting them in a different scope.

Thanks for your thoughts and insights.

My example code follows:

==========================

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

void getNonPunct(string _str, char* &_npcarr, int &_npsize);

int main()
{
    string input_string;    
    char* npchar_arr;
    int npsize;

    cout << "Enter any string: ";
    getline(cin, input_string);

    getNonPunct(input_string, npchar_arr, npsize);    

    // Now display non-punctuation characters in the string
    cout << "string with non-punctuation characters removed:\n";

    for (int n = 0; n <= npsize - 1; n++)
        cout << npchar_arr[n];
    cout << "\n(" << npsize << ") non-punctuation characters\n";    

    // Now return the memory allocated with 'new' to heap

    delete [] npchar_arr;
    // Is it okay to 'delete' npchar_arr eve if it was created in the function
    // getNonPunct() ?

    return(0);
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void getNonPunct(string _str, char* &_npcarr, int &_npsize)    
//This void function takes an input array of strings containing arbitrary
//characters and returns a pointer to an array of characters containing only
//the non-punctuation characters in the input string. The number of
//non-punctuation characters are stored in size. Prior to the function call,
//int_arr and size are undefined. After the function call, char_arr points to
//the first location of an array of the non-punctuation character array.
//'size' is equal to the number of non-punctuation characters in the input
//string. 
{

    // First get the number of non-punctuation characters in the string

    int str_len, npcount = 0;

    str_len = static_cast<int>( _str.length() );

    _npsize = 0;
    for (int i = 0; i <= str_len - 1; i++)
    {
        if ( !ispunct(_str[i]) )
            _npsize++;        
    }

    // Now that you know how many non-punctuation characters are in the string,
    // create a (dynamic) character array of _npsize.

    _npcarr = new char [_npsize];


    for (int k = 0; k <= str_len - 1; k++)
    {
        if ( !ispunct(_str[k]) )
            _npcarr[npcount++] = _str[k];
    }    

    return;
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
RDK
  • 923
  • 1
  • 9
  • 22
  • 1
    Note that in this specific example, `npchar_arr` might as well just be a `std::string` too, and that the whole algorithm could be written as `std::remove_copy_if(source.begin(), source.end(), std::back_inserter(result), (int)(*)(int)std::ispunct)`. – James McNellis Jan 23 '12 at 22:44

3 Answers3

4

Is it valid? Yes. The array pointed to by npchar_arr exists until you destroy it and it is okay to destroy it using a delete[] expression in another function.

Is it a good idea? No. You would be much better off using a smart pointer that manages the lifetime of the object automatically, releasing you from the responsibility of delete[]ing the pointer manually yourself.

Consider using a std::unique_ptr<char[]> if your compiler and Standard Library support unique_ptr, or std::auto_ptr or std::shared_ptr if you cannot use unique_ptr (shared_ptr may also be found in Boost and C++ TR1).

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • James, I am really new to C++. So please be patient with my elementary questions. Are std::unique_ptr and others pre-specified pointer types in the STL or are they something one creates? – RDK Jan 23 '12 at 23:28
  • There's nothing wrong with elementary questions. We all were beginners at some point. :-) `auto_ptr`, `shared_ptr`, and `unique_ptr` are all part of the C++ Standard Library (in ``). `unique_ptr` and `shared_ptr` are relatively new, which is why I mention that your compiler and Standard Library may not support them yet. (Aside: do you have [a good introductory C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)?) – James McNellis Jan 23 '12 at 23:32
  • That list is very helpful James. I am learning from Walter Savitch's book. But I am beginning to understand its limitations and the list you provided with that link would be very helpful in taking me to the next step. – RDK Jan 24 '12 at 00:11
2

Allocating in one scope and deleting in another is one of the major reasons for using dynamic allocation instead of an automatic local variable.

As James says, prefer to use smart pointers to track dynamically allocated objects.

The only constraint I can think of on allocation in one scope and deallocation in another is multi-component applications where different components are built with different compilers (or maybe different versions of the same compiler). On Windows, each compiler provides its own memory management library, and you shouldn't free memory from a different component than the one that allocated it. Or you can use Windows-provided memory management routines which are common to all compilers (e.g. HeapAlloc/HeapFree). On Linux, everyone uses the glibc-supplied malloc, free, new[], and delete[], so it isn't such an issue. For other OSes, you need to investigate.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Or multiple modules built by the same version of a particular compiler, but compiled with different options, or even compiled with the same options, but with the runtime library statically linked into multiple modules. Ah, the joys of programming in C++ on certain platforms. – James McNellis Jan 23 '12 at 23:48
  • @JamesMcNellis: There are a lot of things which potentially break compatibility, but they all lead to the same conclusion: "you shouldn't free memory from a different component than the one that allocated it". – Ben Voigt Jan 24 '12 at 00:13
  • It should also be noted that returning a smart pointer solves this module mismatch problem as well -- since the deleter is chosen in the allocating code. – edA-qa mort-ora-y Jan 24 '12 at 08:28
  • @edA-qamort-ora-y: Not really, you just trade deallocator mismatch for smart pointer layout mismatch. – Ben Voigt Jan 24 '12 at 14:44
0

This example is very trivial, but image the following modification of your code:

int main()
{
    string input_string;    
    char* npchar_arr;
    int npsize;

    cout << "Enter any string: ";
    getline(cin, input_string);

    getNonPunct(input_string, npchar_arr, npsize);    

    // Now display non-punctuation characters in the string
    cout << "string with non-punctuation characters removed:\n";

    for (int n = 0; n <= npsize - 1; n++)
        cout << npchar_arr[n];
    cout << "\n(" << npsize << ") non-punctuation characters\n";    

    return(0); // WHOOPS! I JUST RETURNED AND DIDN'T FREE THE MEMORY

    delete [] npchar_arr;
    // Is it okay to 'delete' npchar_arr eve if it was created in the function
    // getNonPunct() ?

    return(0);

}

I just returned before freeing the memory, which results in a memory leak! Of course, you might be thinking that you would never do such a thing, but imagine a much more complex program, it is easy to make such a mistake as the above, and using smart pointers as the other answers suggest, would alleviate you of having to worry about such tasks.

Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • Thanks Jesse. James' post above was the very first time I have heard about smart pointers. I will look into those now. – RDK Jan 23 '12 at 23:37