gueza
Mira este sencillo código:
struct Point {
int x;
int y;
};
void something(int *);
int main() {
Point p{1, 2};
something(&p.x);
return p.y;
}
Eso espero main
El valor de retorno de se puede optimizar para return 2;
como something
no tiene acceso a p.y
solo recibe un puntero a p.x
.
Pero, ninguno de los principales compiladores optimiza el valor de retorno de main
a 2
. Rayo de Dios.
¿Hay algo en el estándar que permita something
Modificar p.y
si solo damos acceso a p.x
? En caso afirmativo, ¿depende esto de si Point
tiene diseño estándar?
¿Qué pasa si uso something(&p.y);
y return p.x;
¿en cambio?
barry
Esto está perfectamente bien definido:
void something(int *x) {
reinterpret_cast<Point*>(x)->y = 42;
}
los Point
objeto (p
) y es x
miembro son puntero interconvertible, de [basic.compound]:
dos objetos a y b son puntero-interconvertible si:
- […]
- uno es un objeto de clase de diseño estándar y el otro es el primer miembro de datos no estáticos de ese objeto o, si el objeto no tiene miembros de datos no estáticos, cualquier subobjeto de clase base de ese objeto ([class.mem]), o:
- […]
Si dos objetos son punteros interconvertibles, entonces tienen la misma dirección y es posible obtener un puntero a uno de un puntero al otro a través de un
reinterpret_cast
.
Que reinterpret_cast<Point*>(x)
es válido y termina con un puntero que apunta a p
. Por lo tanto, modificarlo directamente está bien. Como puede ver, la parte de diseño estándar y la primera parte del miembro de datos no estáticos son significativas.
Aunque no es que los compiladores en cuestión optimicen la carga adicional si pasa un puntero a p.y
entrar y volver p.x
en cambio.
-
Gracias, sabía que dejé un hueco en mi pregunta. Entonces, si usé
something(&p.y); return p.x;
entonces es claramente una optimización perdida?– geza
17 sep 2019 a las 17:24
-
@geza Técnicamente, sí, sería una optimización perdida entonces, pero no creo que los principales compiladores, en este momento, estén preparados para romper todo el código existente que usa
offsetof
.– Brian Bi
17 sep 2019 a las 17:29
-
¿Eso no viola la regla de alias estricto? ¿O es una regla de solo C?
– stucotte06
17/09/2019 a las 17:40
-
@ sturcotte06 no lo hace por Si dos objetos son punteros interconvertibles, entonces tienen la misma dirección y es posible obtener un puntero a uno de un puntero al otro a través de reinterpret_cast.
– NathanOliver
17/09/2019 a las 17:40
-
¿Me estoy perdiendo de algo? el elenco cambia el puntero a
p.x
en un puntero aPoint
pero no obstante, sigue apuntando a la misma ubicación de memoria? Eso significaría que esto solo funciona porquex
es el primer miembro y, por lo tanto, existe en la misma ubicación de memoria que el objeto ‘principal’Point p
? Así que si tuviéramos que pasar&p.y
en la función, obtendríamos un comportamiento diferente (¿indefinido?)– Baldrickk
18 de septiembre de 2019 a las 9:06
No entiendo el voto negativo y la bandera. Esta es una pregunta perfectamente razonable para mí.
– Zereges
17 sep 2019 a las 17:13
stackoverflow.com/questions/50803202/… “Los requisitos de alineación de la implementación pueden hacer que dos miembros adyacentes no se asignen inmediatamente uno detrás del otro”
– alter_igel
17 sep 2019 a las 17:13
@alterigel: esto no debería importar, ya que podemos usar
offsetof
. Pero no estoy seguro de que podamos obtener un puntero parap.y
dep.x
con las nuevas reglas semánticas de punteros de C++17.std::launder
no se puede utilizar, como un puntero ap.x
solo puede alcanzarp.x
. Entonces, incluso si pudiera mover el puntero a la ubicación correcta, tal vez ese puntero no apunte al objeto dep.y
.– geza
17 sep 2019 a las 17:17
Si lo cambias a
void something(int * x) { *(x+1) = 6; }
optimiza el valor de retorno a un valor fijo6
por lo que el compilador al menos ve eso como una opción válida para hacer.– t.niese
17 sep 2019 a las 17:20
@zereges, no voté en contra, pero casi lo hice. La pregunta es muy difícil de analizar. Creo que el OP pregunta: “¿por qué el compilador no puede darse cuenta de que la función something () no modificará py?” Si el OP preguntara eso directamente, habría menos votos negativos.
– Jeffrey
17 sep 2019 a las 17:26