2

Is the following safe?

struct K { ... }

struct A
{
    A(int psize) : size(psize), foo(nullptr), bar(nullptr)
    {
        auto dataptr = (K*)_aligned_malloc(sizeof(K) * psize * 2, 32);
        data = shared_ptr<K>(dataptr, ptr_fun(_aligned_free));
        foo = data.get();
        bar = data.get() + psize;
    }   
    K* __restrict foo;
    K* __restrict bar;
private:
    shared_ptr<K> data;
};

Note the __restrict on foo and bar.

The goal is to have allocated memory self destruct when all object aliases have died.

{
    A a(1000);
    { 
        A o = a; 
    }
    //a.foo is still valid
}
//a.foo is invalid
Mat
  • 202,337
  • 40
  • 393
  • 406
jameszhao00
  • 7,213
  • 15
  • 62
  • 112

2 Answers2

2

You don't need __restrict qualifiers here, and in fact you shouldn't use them, because __restrict is supposed to tell the compiler that you don't have any aliases to the same memory, but in fact you do have aliases -- foo and data are aliases to the same memory.

I think the semantics of your code are fine, otherwise. Your a.foo is still valid and a.foo is invalid conditions will be true.

James Brock
  • 3,236
  • 1
  • 28
  • 33
  • `__restrict` is a compiler optimization only, it doesn't change the behavior of your program. – James Brock Oct 24 '11 at 01:41
  • Yep. Was hoping a logical guarantee that foo won't be modified elsewhere would be enough for a __restrict (i.e. the memory is aliased, but I promise I won't change it except from foo). Until the object dies of course. – jameszhao00 Oct 24 '11 at 01:54
  • Yeaahhh.... I think you should be super-careful about using __restrict like that. If you only have one instance of `A`, then maybe you can get away with it, but your use case clearly indicates that you want to be able to copy-assign `A`, in which case you have memory which is pointed to by two `shared_ptr`s and two `__restrict`ed pointers... very bad situation. – James Brock Oct 24 '11 at 02:45
  • Ah I see. Didn't consider the copy construct. Thanks! – jameszhao00 Oct 24 '11 at 05:17
0

That is not safe because malloc doesn't call the constructor and free doesn't call the destructor. For that to be safe you need to manually add those calls:

A(int psize) : size(psize), foo(nullptr), bar(nullptr)
{
    auto dataptr = (K*)_aligned_malloc(sizeof(K) * psize * 2, 32);
    new(dataptr) K();
    data = shared_ptr<K>(dataptr, [](K *k){ k->~K(); _aligned_free(k) ));
    foo = data.get();
    bar = data.get() + psize;
}
Daniel
  • 30,896
  • 18
  • 85
  • 139