Pregunta

Nota: Para aclarar, la pregunta no se trata del uso de restrict Palabra clave en general, pero específicamente sobre la aplicación a las funciones de los miembros como se describe aquí.

GCC le permite usar el __restrict__ (El GNU ++ equivalente a C99's restrict) Calificador en una función de miembro, haciendo efectivamente this Un puntero calificado restringido dentro del alcance de la función. ¿Dónde está la carne?

La mayoría de las funciones de los miembros trabajan en otros miembros, accediendo a ellas a través de this, el cual es un T* const (y normalmente no se realizan). Para this Para estar posiblemente alias, tendría que haber un segundo puntero a tipo en uso dentro de la función miembro de alguna manera, y tendría que venir de algún lugar.
Esa es una situación que regularmente es el caso con las funciones no miembros, como, por ejemplo, todos los operadores binarios o cualquier otra función libre que tome al menos dos punteros o referencias de un tipo idéntico y no trivial. Sin embargo, estas funciones no tienen un this, por lo que no son relevantes.

El operador de asignación, el constructor de copias y los operadores de comparación unía son ejemplos de funciones miembros donde this pudo en principio, sea alias (ya que otro objeto se pasa por referencia). Por lo tanto, solo tiene sentido asignar un calificador restringido a estos: ya debería ser obvio para el compilador que todas las demás funciones tienen la propiedad restringida de todos modos (porque nunca hay un segundo puntero a T).

Ahora, si por ejemplo usaste restrict en operator= debería importantemente no verificar la autoasignación en absoluto, porque estás diciendo eso this no está alias dentro del alcance de esa función (y Si eso es cierto, no puede suceder una autoasignación).
Obviamente, esto es algo que no puede conocer de antemano, y es algo que tampoco tiene sentido.

Entonces, ¿cuál sería un caso en el que uno quisiera darle a un miembro una función restringida y dónde tiene sentido?

¿Fue útil?

Solución

O me falta algo o su pregunta no tiene sentido. this no es que A diferencia de cualquier otro argumento a una función de miembro, entonces, ¿por qué te sorprende que GCC te permita aplicar? restrict ¿lo?

Con respecto a la aplicación a un operador de asignación, señala con razón que obviaría la necesidad de una prueba de autoasignación explícita. Luego tu dices:

Obviamente, esto es algo que no puedes saber de antemano

Pero esto es siempre verdadero cuando usas restrict por nada. Por ejemplo, alguien podría decidir llamar memcpy con regiones de memoria superpuestas; "No se puede saber de antemano" que no lo harán. Pero el restrict declaración para los argumentos de memcpy medio han cometido un error si lo hacen. De la misma manera, si declara un operador de asignación restrict, ha cometido un error para alguien a los objetos autoensignados de esa clase. No hay nada misterioso o contradictorio en esto en absoluto; Es solo parte de la semántica de restrict que impone ciertas restricciones en el resto de su código.

Tampoco estoy seguro de por qué le resulta tan imposible que la función de un miembro tome un puntero (o referencia) a otro objeto del mismo tipo. Ejemplo trivial:

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

Este tipo de cosas se cultiva todo el tiempo.

Entonces la verdadera pregunta es, ¿por qué piensas? this ¿Es tan diferente de cualquier otro argumento? O si lo prefieres, ¿cómo extrañé tu punto tan por completo?

Otros consejos

Creo que lo que se están perdiendo es que un argumento para la función de un miembro también podría alias partes o un objeto. Aquí hay un ejemplo

struct some_class {
    int some_value;

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

Probablemente uno esperaría que se compilara para

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

Ese código, desafortunadamente, sería equivocado Si alguien pasa una referencia a algún_value para el resultado. Por lo tanto, un compilador realmente necesitaría generar a continuación

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

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

que obviamente es mucho menos eficiente. Tenga en cuenta que a menos que compute_something sea incrustado, el compilador tiene no forma de saber si el resultado puede alias algún_value o no, por lo que posee Para asumir el peor de los casos, no importa que no sea inteligente o tonto. Por lo tanto, hay una ventaja definitiva y muy real para restringir, incluso si se aplica a este puntero.

El enlace que publicaste es interesante. No habrá un caso de uso sólido para tener restrict aplicado en this. Como mencionó en su pregunta, Copy Constructor, operador = podría haber sido candidatos potenciales; Pero el compilador puede cuidarlos.

Pero seguir el caso puede ser interesante

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

Ahora el caso de uso puede ser;

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;

Aunque esta es una práctica muy inusual, este es el único caso que podría pensar en este caso de uso.

Me temo que no entiendo claramente por qué estás hablando de this.

restrict Especifica que un puntero no está superpuesto con los demás. Por lo tanto, los compiladores pueden asumir que las regiones de memoria señaladas por restricción de punteros no dependen, lo que permite optimizaciones más agresivas. __restrict__ sería mucho más efectivo cuando se usa para otras variables de puntero que this.

Entonces, ¿cuál sería un caso en el que uno quisiera darle a un miembro un calificador restringido y dónde tiene sentido?

Solo recuerde un caso representativo de usar restrict punteros en memcpy:

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

Agregar esto como una respuesta, porque probablemente sea más adecuado como tal (es una especie de respuesta y realmente no pertenece a la pregunta, además es un poco largo para un comentario).

Después de pensar en la respuesta de Nemo durante mucho tiempo, creo que nuestra interpretación sobre la autoasignación es quizás algo incorrecta (aunque la de Nemo era más correcta que la mía). Como Nemo señaló correctamente, tener un restrictivo calificado this En realidad significa que la presencia de alias es un error de programa. Ni mas ni menos.

En la medida en que al escribir esto, su lógica en realidad no debería ser "ya que usted dice que esto no puede suceder, en consecuencia no debe verificar la autoasignación", sino "ya que explícitamente dice que el alias no puede suceder, y es un error del programa si usted lo hace no solo Necesita verificar la autoasignación, pero en consecuencia deber Falling duro si sucede ".

Y, en la medida en que enfatiza una lógica de programa en particular y al mismo tiempo permite al compilador optimizar mejor para ese caso especial en particular y, por lo tanto, De hecho tiene sentido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top