Domanda

Nota: Per chiarire, la questione non riguarda l'uso della parola chiave restrict in generale, ma in particolare su applicandolo a funzioni membro come descritto qui .

gcc consente di utilizzare il __restrict__ (la GNU ++ equivalente a restrict di C99) qualificazione su una funzione membro, di fatto rendendo this un puntatore limitare qualificato nel campo di applicazione della funzione. Dov'è il manzo?

La maggior parte delle funzioni membro lavorare su altri membri, accedervi tramite this, che è un T* const (e normalmente unaliased). Per this da possibilmente alias, non ci sarebbe bisogno di essere un secondo tipo puntatore-a-in uso all'interno della funzione membro in qualche modo, e sarebbe dovuto venire da qualche parte.
Questa è una situazione che è il caso con funzioni terzi, come ad esempio tutti gli operatori binari o qualsiasi altra funzione libero che richiede almeno due puntatori o riferimenti di un tipo non banale identici. Tuttavia, queste funzioni non hanno una this, quindi non sono rilevanti.

L'operatore di assegnazione, costruttore di copia, e operatori di confronto unari sono esempi di funzioni membro dove this potrebbe in linea di principio essere alias (poiché un altro oggetto viene passato tramite riferimento). Quindi ha veramente solo senso per assegnare un qualificatore limitare a questi - dovrebbe già essere ovvio per il compilatore che tutte le altre funzioni hanno la proprietà limitare in ogni caso (perché non c'è mai un secondo puntatore-a-T)

.

Ora, se per esempio si è utilizzato restrict su operator= si dovrebbe di conseguenza non verificare la presenza di auto-assegnazione a tutti, perché stai dicendo che non è this alias nell'ambito di applicazione di quella funzione (e se questo è vero , nessuna auto-assegnazione può accadere).
Ovviamente, questo è qualcosa che non si può saperlo in anticipo, ed è qualcosa che non ha senso neanche.

Quindi, che cosa sarebbe un caso in cui ci si vuole realmente dare una funzione di membro di limitare qualificazione e dove ha senso?

È stato utile?

Soluzione

In entrambi mi manca qualcosa, o la tua domanda non ha senso. this non è che diverso da qualsiasi altro argomento a una funzione di membro, quindi perché siete sorpresi che GCC permette di applicare restrict ad esso?

Per quanto riguarda la sua applicazione ad un operatore di assegnazione, giustamente sottolineano che sarebbe ovviare alla necessità di un test di auto-assegnazione esplicita. Poi dici:

Ovviamente, questo è qualcosa che non si può saperlo in anticipo

Ma questo è sempre vero quando si utilizza restrict per qualsiasi cosa. Per esempio, qualcuno potrebbe decidere di chiamare memcpy con sovrapposizione regioni di memoria; si "non puoi sapere in anticipo" che non lo faranno. Ma la dichiarazione restrict per gli argomenti di mezzi memcpy hanno commesso un errore se lo fanno . Esattamente nello stesso modo, se si dichiara un restrict operatore di assegnazione, avete fatto un errore che qualcuno gli oggetti auto-assegnazione di questa categoria. Non c'è nulla di misterioso o contraddittorie su questo a tutti; è solo una parte della semantica di restrict che impone alcuni vincoli sul resto del codice.

Sono anche sicuro perché a trovarlo così impossibile per una funzione membro di prendere un puntatore (o di riferimento) a un altro oggetto dello stesso tipo. Trivial esempio:

class Point {
public:
    double distance(const Point &other) const;
};

Questo genere di cose affiora tutto il tempo.

Quindi la vera domanda è, perché pensi che this è così diverso da qualsiasi altro argomento? Oppure, se preferite, come mi sono perso il vostro punto in modo completamente?

Altri suggerimenti

I belive quello che voi ragazzi mancano è che un argomento a una funzione membro potrebbe anche alias parti o un oggetto. Ecco un esempio

struct some_class {
    int some_value;

    void compute_something(int& result) {
        result = 2*some_value;
        ...
        result -= some_value;
    }
}

Si potrebbe probabilmente si aspettano che per la compilazione a

*(this + offsetof(some_value)) -> register1
2*register1 -> register2
...
register2 - register1 -> result

Questo codice, purtroppo, sarebbe sbagliato se qualcuno passa un riferimento a some_value per il risultato. Così, un compilatore sarebbe in realtà bisogno di generare a seguito

*(this + offsetof(some_value)) -> register1
2*register1 -> register2
register2 -> result

...
*(this + offsetof(some_value)) -> register1
result -> register2
register2 - register1 -> register2
register2 -> result

che è ovviamente modo meno efficiente. Nota che se non compute_something è inline, il compilatore ha non modo di sapere se risultato può alias some_value o no, in modo che ha per assumere il caso peggiore, non importa, non intelligente o muto è. Quindi c'è un indubbio vantaggio e molto reale per limitare, anche se applicata al puntatore this.

The link you posted is interesting. There will not be a solid use case for having restrict applied on this. As you mentioned in your question, copy constructor, operator = could have been potential candidates; but compiler can take care of them.

But following case can be interesting

struct A
{
  //...
  void Destroy (A*& p) __restrict__
  {
    delete this;
    p = 0;
    p++;
  }
};

Now use case can be;

A **pp = new A*[10];
for(int i = 0; i < 10; i++)
  pp[i] = new A;
//...
A* p = pp[0];
for(int i = 0; i < 10; i++)
  p->Destroy(p);
delete[] pp;

Though this is very unusual practice, this is the only case I could think of this use case.

I'm afraid that I don't clearly understand why you're talking about this.

restrict specifies that a pointer is not overlapped with others. So, compilers can assume the memory regions pointed by restrict pointers are not dependent, which allows more aggressive optimizations. __restrict__ would be much more effective when used for other pointer variables than this.

So, what would be a case where one would actually want to give a member a restrict qualifier and where it makes sense?

Just recall a representative case of using restrict pointers in memcpy:

void Foo::MyCompute(__restrict__ char* bufA, __restrict__ char* BufB)
{
}

Adding this as an answer, because it's probably better suited as such (it's kind of an answer and doesn't really belong to the question, plus it's a bit long for a comment).

After thinking about Nemo's answer for a long time, I believe that our both interpretation about self-assignment is maybe somewhat wrong (though Nemo's was more correct than mine). As Nemo correctly pointed out, having a restrict-qualified this actually means that presence of aliasing is a program error. No more, no less.

Insofar, when writing this, your logic should actually not be "since you say this cannot happen, you consequentially should not check for self-assignment", but rather "since you explicitly say that aliasing cannot happen, and it's a program error if it does, you not only need to check for self-assignment, but you consequentially must fail hard if it happens".

And, insofar, it emphasizes a particular program logic and at the same time allows the compiler to optimize better for that particular special case, and thus does indeed make sense.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top