9

Smart pointers are pointers underneath, so is there any way of defining a shared_ptr parameter to a function as not aliasing another shared_ptr, or another pointer of any sort?

Or is this, for some reason, unnecessary?

I'm concerned with the gcc >=4.2 and llvm-clang >=2.0 compilers (answers for other compilers would also be interesting).

Mat
  • 202,337
  • 40
  • 393
  • 406
James
  • 24,676
  • 13
  • 84
  • 130
  • C++ doesn't have any `restrict` or `__restrict__` keyword. If you're asking about language extensions in a particular compiler, you need to say which. – Ben Voigt Jan 29 '12 at 00:29
  • @BenVoigt sorry - clarified in edit. – James Jan 29 '12 at 00:35
  • 3
    It seems unlikely that a finction wanting to work on restricted pointers wants to claim shared ownership of the pointer. Not to mention that in a system with shared ownership you end up knowing that the pointers are indeed distinct. In any case, I'd guess your function actualky wants to take [restricted] pointers rather than `std::shared_ptr`s. – Dietmar Kühl Jan 29 '12 at 00:55

2 Answers2

8

Just extract the pointers with .get() and mark them as __restrict__. Remember, putting __restrict__ into the function parameters is the same as putting __restrict__ on local variables. In particular, the compiler doesn't attempt to stop you from calling the function with two pointers that obviously point to the same object; e.g. foo(i,i).

If you want to make a promise to the compiler that certain pointers don't reference each other, allowing the compiler to do more optimizations, then use this code below and do your operations through xp and yp instead of x and y.

#include<iostream>
#include<memory>
using namespace std;

void foo(shared_ptr<int> x, shared_ptr<int> y) {
        int * __restrict__ xp = x.get();
        int * __restrict__ yp = y.get();
}

int main() {
        shared_ptr<int> i = make_shared<int>(3);
        shared_ptr<int> j = make_sharet<int>(4);
        foo(i,j);
}
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 2
    Why do you say that marking function parameters as `restrict` is different to declaring local `restrict` pointer variables? Is that something to do with `gcc` optimisation or is it an underlying behaviour of `restrict` (that I don't currently understand ;) ) – Darren Engwirda Jan 29 '12 at 00:58
  • 1
    I say it's *not* different. I'll try to reword it to be more clear. – Aaron McDaid Jan 29 '12 at 01:11
  • I was going to write this, but I couldn't find ANY grammar for `__restrict__` that said whether it was allowed on local variables. Is there documentation somewhere? – Ben Voigt Jan 29 '12 at 01:57
  • 1
    @BenVoigt `restrict` is defined as a *type-qualifier* just like `const` and `volatile` (C99 §6.7.3/1). `__restrict__` is a GCC extension and might not be precisely defined by any formal grammar, even if one exists. – Potatoswatter Jan 29 '12 at 02:10
  • agreed, @BenVoigt ! Edited so they don't alias. I think I was intending to talk about that in the answer, but I forgot and left this error without discussing it. – Aaron McDaid Jan 29 '12 at 02:14
5

If you want to perform non-aliased operations on the underlying object associated with a shared pointer you could explicitly delegate to a worker routine that takes a non-aliased pointer parameter:

void worker (mytype *__restrict x, mytype *__restrict y)
{
    // do something with x, y with a no-alias guarantee
}

int main()
{
    std::shared_ptr<mytype> p(new mytype);
    std::shared_ptr<mytype> q(new mytype);

// explicitly delegate the shared object
    worker(p.get(), q.get());

    return 0;
}

I'm not sure exactly what you have in mind, but this would allow the high-level memory management to be dealt with safely by the smart pointer, while doing the low level work possibly more efficiently with no-alias pointers.

As @BenVoigt pointed out, restrict is only offically part of c99 - c++ isn't supposed to know anything about it. MSVC supports it anyway via __restrict and as you've said GCC has __restrict__.

Hope this helps.

Darren Engwirda
  • 6,915
  • 4
  • 26
  • 42