1

I am looking for a clean way to manage scope of arrays using the new pointer templates introduced in C++11, the typical scenario here is when calling into win32 api functions.

I am posting here because though there is plenty of discussion on more complex matters this relatively simple scenario doesn't seem to have been discussed and I'm wondering if there are better options than what I am now starting to do.

#include <memory>

void Win32ApiFunction(void* arr, int*size)
{
    if(arr==NULL)
        *size = 10;
    else
    {
        memset(arr,'x',10);
        ((char*)arr)[9]='\0';
    }
}

void main(void)
{
    // common to old and new
    int size;
    Win32ApiFunction(NULL,&size);

    // old style - till now I have done this for scope reasons
    if(char* data = new char[size])
    {
        Win32ApiFunction(data,&size);
        // other processing
        delete [] data;
    }

    // new style - note additional braces to approximate
    // the previous scope - is there a better equivalent to the above?
    {
        std::unique_ptr<char[]> data1(new char[size]);
        if(data1)
        {
            Win32ApiFunction(data1.get(),&size);
            // other processing
        }
    }
}
ildjarn
  • 62,044
  • 9
  • 127
  • 211
dice
  • 2,820
  • 1
  • 23
  • 34
  • 5
    In either case new will throw an exception on allocation failure, not return 0. – karunski Feb 23 '12 at 12:14
  • 1
    For most real Win32 API functions, you need to initialise "size" to 0 before the first call. – user9876 Feb 23 '12 at 12:24
  • 1
    If you need to zero initialize the array prior to the second call then `std::vector` is superior (because it will do so automatically and fast). If you don't need to zero the array, what you have is superior to `std::vector` because it doesn't spend the cycles doing that unneeded zero initialization. And if you're not in a context that demands the very highest performance, it isn't going to matter which you use. – Howard Hinnant Feb 23 '12 at 13:35
  • 2
    And don't forget `new char[size]()`. – Johannes Schaub - litb Feb 25 '12 at 21:12

1 Answers1

11

The cleanest way is to use std::vector, even C++98 guarantees that it is compatible with C-style arrays (i.e. it is stored as single continuous block), all you need is to pass pointer to the first element to your Win32ApiFunction.

std::vector<char> data(size);
Win32ApiFunction(&data[0], &size);

In C++11 there is a special member function std::vector<T>::data() which returns the pointer to the beginning of the array (so you do not need to bother about overloaded operator& () for the vector value type and using std::addressof, see How can I reliably get an object's address when operator& is overloaded? for C++98 issues with operator&() overloading).

Community
  • 1
  • 1
Begemoth
  • 1,389
  • 9
  • 14
  • 1
    I think you want std::vector here. – karunski Feb 23 '12 at 12:15
  • 1
    Note that there's a special method for that in C++11: [`std::vector::data`](http://en.cppreference.com/w/cpp/container/vector/data), which will return the pointer to the beginning of the array. – Xeo Mar 01 '12 at 23:22
  • 1
    It's possible that the API call would return size == 0. In that case, your vector has zero elements, and taking a reference to the first element &data[0] is undefined. It may and frequently does work without issue on some platforms, but a debug build might fail because of the out-of-bounds access. I believe this is one reason why data() was added to C++11. – James Johnston Jul 28 '12 at 01:25