1

Say I have a class:

class A
{
  private:
    const int * const v;
  public:
    A();
}

I want v to be allocated in the initialization list, and I think I can define the following constructor:

A::A():v((int*)malloc(10*sizeof(int))){}

However, what about v has to be allocated in a non-standard way like the following:

cudaMalloc(&v,10*sizeof(int));

Note cudaMalloc is a CUDA API to allocate GPU memory.

Hailiang Zhang
  • 17,604
  • 23
  • 71
  • 117

2 Answers2

8

(Ignoring the bigger-picture matters of overall design, exception safety etc. and focusing on the question in its most narrow scope)

Abandon the idea of doing in the initializer list and do it in the constructor body instead

A::A() : v(NULL)
{
  cudaMalloc(&v, 10 * sizeof(int));
}

Or, alternatively, wrap the allocation function into your own function that returns the pointer

void *wrapped_cudaMalloc(size_t size)
{
  void *m = NULL;
  cudaMalloc(&m, size);
  return m;
}
...

A::A() : v(wrapped_cudaMalloc(10 * sizeof(int)))
  {}

Just for the sake of completeness, there's also an ugly convoluted way to do it in the initializer list without creating any wrappers by exploiting the properties of , operator

A::A() : v((cudaMalloc(&v, 10 * sizeof(int)), v))
  {}

Note the additional pair of () around the comma-expression, which is needed to satisfy the initialization syntax (otherwise , will be treated as argument separator instead of comma operator).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    I wouldn’t call this use of the comma operator particularly ugly, nor convoluted, but wrapping `cudaMalloc` is the better choice. – Jon Purdy May 23 '13 at 23:30
  • 1
    @Jon Purdy: The part that strikes me as ugly is that it essentially initializes `v` from `v`. The same thing can be done in arguably "less ugly" way as `v(cudaMalloc(&tmp, 10 * sizeof(int)), tmp)`, where `tmp` is some temporary variable declared elsewhere. But unfortunately it requires an extra variable. – AnT stands with Russia May 23 '13 at 23:35
  • Thanks! The third one is attractive, but it failed. Probably because cudaMalloc returns a non-void value? – Hailiang Zhang May 23 '13 at 23:51
  • 2
    @Hailiang Zhang: The third method is not sensitive to what `cudaMalloc` returns. I fixed the syntax: it required an additional pair of `()`. – AnT stands with Russia May 24 '13 at 00:25
3

In addition to AndreyT's excellent post (and his creative use of the comma operator), you could also wrap things up thusly:

class cudaMallocedInt
{
private:
    int *v;

public:
    cudaMallocedInt(int n)
    {
        cudaMalloc(&v, n * sizeof(int));
    }

    cudaMallocedInt(const cudaMallocedInt &o)
    {  
        // Do whatever is appropriate here. Probably some sort of dance.
    }

    ~cudaMallocedInt()
    {
        // Remember to cudaFree or whatever
    }

    operator int*()
    {
        return v;
    }
};

class A
{
private:
    cudaMallocedInt v;

public:
    A()
        : v(10)
    {
    }

    ...
};

Update: As Johnsyweb pointed out in comments, please be sure to adhere to the Rule of Three to make sure things don't go boom and you waste your weekends tracking down hard to debug errors instead of having fun!

Community
  • 1
  • 1
Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37