Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Que hacen los dos puntos aqui

Estas en el tema de Que hacen los dos puntos aqui en el foro de C/C++ en Foros del Web. Código: class Point { int i, j, k; public: Point(): i(0), j(0), k(0) {} Point(int ii, int jj, int kk) : i(ii), j(jj), k(kk) {} ...
  #1 (permalink)  
Antiguo 27/09/2009, 09:06
 
Fecha de Ingreso: octubre-2008
Mensajes: 50
Antigüedad: 15 años, 6 meses
Puntos: 2
Que hacen los dos puntos aqui

Código:
class Point {
int i, j, k;
public:
Point(): i(0), j(0), k(0) {}
Point(int ii, int jj, int kk)
: i(ii), j(jj), k(kk) {}
void print(const string& msg = "") const {
if(msg.size() != 0) cout << msg << endl;
cout << "i = " << i << ", "
<< "j = " << j << ", "
<< "k = " << k << endl;
}
};
que hace exactamente esta linea

Point(): i(0), j(0), k(0) {}

ese tipo de sintaxis nunca la había visto
  #2 (permalink)  
Antiguo 27/09/2009, 11:28
Avatar de r0d
r0d
 
Fecha de Ingreso: noviembre-2007
Mensajes: 86
Antigüedad: 16 años, 5 meses
Puntos: 3
Respuesta: Que hacen los dos puntos aqui

Hola,

eso es lo que se llama la "lista de inicializadores" de un constructor.
Por ejemplo, este codigo:
Código:
Point(): i(0), j(0), k(0) {}
hace la misma cosa que este:
Código:
Point()
{ 
   i=0;
   j=0;
   k=0;
}
Bueno, la verdad es que hay diferencias entre estos 2 maneras de hacer*, pero es un poco complicado, y para empesar, se puede considerar que es igual.


*En la secunda, se creen 3 variables temporales, asi que la primera manera de hacer (con lista de inicializadores) es mas eficiente. Y la verdad es que es mas segura, porque si todos los miembros de una clase son intializados en aquella lista, estas seguro que esta clase respeta el RAII.
  #3 (permalink)  
Antiguo 28/09/2009, 05:11
Avatar de Eternal Idol  
Fecha de Ingreso: mayo-2004
Ubicación: Lucentum
Mensajes: 6.192
Antigüedad: 20 años
Puntos: 74
Respuesta: Que hacen los dos puntos aqui

r0d: ¿Podes demostrar esa diferencia con alguna documentacion o codigo generado por un compilador?

Yo no veo ninguna necesidad de usar variables temporales (a fin de cuentas se esta asignando un valor a un miembro de la clase) y en la practica con VC++ el codigo generado es identico. Usar esa sintaxis no te garantiza inicializar todos los miembros, podes olvidarte de algunos perfectamente.
__________________
¡Peron cumple, Evita dignifica! VIVA PERON CARAJO
  #4 (permalink)  
Antiguo 28/09/2009, 08:12
Avatar de r0d
r0d
 
Fecha de Ingreso: noviembre-2007
Mensajes: 86
Antigüedad: 16 años, 5 meses
Puntos: 3
Respuesta: Que hacen los dos puntos aqui

Cita:
Iniciado por Eternal Idol Ver Mensaje
r0d: ¿Podes demostrar esa diferencia con alguna documentacion o codigo generado por un compilador?
Lo que pasa es que los compiladores modernos optimizan esto (reemplazan el operador de asignación por el constructor). Pero cuando la variable miembra es un objeto un poco complicado, no puede. Asi que, si fijaos el codigo siguiente por ejemplo:

Código:
#include <string>
#include <iostream>
 
struct Human {
    Human():
    name("John Doe"),
    id(492)
    {}
 
    Human(const std::string& name_, int id_):
    name(name_),
    id(id_)
    {}
 
    std::string name;
    int id;
};
 
struct B {
    B(const Human& a):a_(a) {}
    Human a_;
};
 
struct C {
    C(const Human& a) {
        a_ = a;
    }
 
    Human a_;
};
 
int main()
{
    Human a("Name", 5); 
    B b(a);
    C c(a);

    std::cin.get();
}
El asm del constructor de B y de C seran diferentes. Por ejemplo, compilado con visual c++ 2008 express ed, asi sale el de B:
Cita:
struct B
{
B(const Human& a):a_(a)
{
00411630 push ebp
00411631 mov ebp,esp
00411633 sub esp,0CCh
00411639 push ebx
0041163A push esi
0041163B push edi
0041163C push ecx
0041163D lea edi,[ebp-0CCh]
00411643 mov ecx,33h
00411648 mov eax,0CCCCCCCCh
0041164D rep stos dword ptr es:[edi]
0041164F pop ecx
00411650 mov dword ptr [ebp-8],ecx
00411653 mov eax,dword ptr [a]
00411656 push eax
00411657 mov ecx,dword ptr [this]
0041165A call Human::Human (4110D7h)
}
0041165F mov eax,dword ptr [this]
00411662 pop edi
00411663 pop esi
00411664 pop ebx
00411665 add esp,0CCh
0041166B cmp ebp,esp
0041166D call @ILT+345(__RTC_CheckEsp) (41115Eh)
00411672 mov esp,ebp
00411674 pop ebp
00411675 ret 4
y asi el asm de C:
Cita:
struct C
{
C(const Human& a)
00411770 push ebp
00411771 mov ebp,esp
00411773 push 0FFFFFFFFh
00411775 push offset __ehhandler$??0C@@QAE@ABUHuman@@@Z (414A98h)
0041177A mov eax,dword ptr fs:[00000000h]
00411780 push eax
00411781 sub esp,0CCh
00411787 push ebx
00411788 push esi
00411789 push edi
0041178A push ecx
0041178B lea edi,[ebp-0D8h]
00411791 mov ecx,33h
00411796 mov eax,0CCCCCCCCh
0041179B rep stos dword ptr es:[edi]
0041179D pop ecx
0041179E mov eax,dword ptr [___security_cookie (418004h)]
004117A3 xor eax,ebp
004117A5 push eax
004117A6 lea eax,[ebp-0Ch]
004117A9 mov dword ptr fs:[00000000h],eax
004117AF mov dword ptr [ebp-14h],ecx
004117B2 mov ecx,dword ptr [ebp-14h]
004117B5 call Human::Human (411181h)
004117BA mov dword ptr [ebp-4],0
{
a_ = a;
004117C1 mov eax,dword ptr [ebp+8]
004117C4 push eax
004117C5 mov ecx,dword ptr [ebp-14h]
004117C8 call Human::operator= (4111FEh)
}
004117CD mov dword ptr [ebp-4],0FFFFFFFFh
004117D4 mov eax,dword ptr [ebp-14h]
004117D7 mov ecx,dword ptr [ebp-0Ch]
004117DA mov dword ptr fs:[0],ecx
004117E1 pop ecx
004117E2 pop edi
004117E3 pop esi
004117E4 pop ebx
004117E5 add esp,0D8h
004117EB cmp ebp,esp
004117ED call @ILT+345(__RTC_CheckEsp) (41115Eh)
004117F2 mov esp,ebp
004117F4 pop ebp
004117F5 ret 4
No soy experto en asm, pero creo que lo que pasa aquí es que en el constructor de B, el constructor de Human es "inlined".

Cita:
Iniciado por Eternal Idol Ver Mensaje
Usar esa sintaxis no te garantiza inicializar todos los miembros, podes olvidarte de algunos perfectamente.
Lo que queria decir, es que si un programador se acostumbra a hacerlo sistemáticamente, y para todas sus variables miembres, estara seguro que su clase esta inicializada correctamente y respeta el RAII.
  #5 (permalink)  
Antiguo 28/09/2009, 08:44
Avatar de Eternal Idol  
Fecha de Ingreso: mayo-2004
Ubicación: Lucentum
Mensajes: 6.192
Antigüedad: 20 años
Puntos: 74
Respuesta: Que hacen los dos puntos aqui

Cita:
Iniciado por r0d Ver Mensaje
Lo que pasa es que los compiladores modernos optimizan esto (reemplazan el operador de asignación por el constructor). Pero cuando la variable miembra es un objeto un poco complicado, no puede. Asi que, si fijaos el codigo siguiente por ejemplo:
No estoy del todo de acuerdo, me parece que el caso que expones es la excepcion a la regla y la optimizacion se produce en la inicializacion con respecto al constructor (en B se llama al constructor copia, en C al constructor por defecto y despues al operarador =). La variable local se usa en este caso que mostras por necesitar hacer una copia del objeto pero en condiciones normales de una asignacion simple no se necesita usar ninguna variable local en lo absoluto, por ejemplo si usara punteros a Human en B y C los constructores serian iguales.

PD. Tambien hay bastante codigo de mas en C por el hecho de que un constructor puede lanzar una excepcion, al optimizar llamando solo al operador de asignacion se omite el manejo de excepciones del constructor de B. El constructor de Human no esta inline, sino verias la asignacion de 0x1EC, directamente no es llamado por B.
__________________
¡Peron cumple, Evita dignifica! VIVA PERON CARAJO

Última edición por Eternal Idol; 28/09/2009 a las 09:22
  #6 (permalink)  
Antiguo 28/09/2009, 14:10
Avatar de r0d
r0d
 
Fecha de Ingreso: noviembre-2007
Mensajes: 86
Antigüedad: 16 años, 5 meses
Puntos: 3
Respuesta: Que hacen los dos puntos aqui

Cita:
Iniciado por Eternal Idol Ver Mensaje
No estoy del todo de acuerdo, me parece que el caso que expones es la excepcion a la regla y la optimizacion se produce en la inicializacion con respecto al constructor (en B se llama al constructor copia, en C al constructor por defecto y despues al operarador =). La variable local se usa en este caso que mostras por necesitar hacer una copia del objeto pero en condiciones normales de una asignacion simple no se necesita usar ninguna variable local en lo absoluto, por ejemplo si usara punteros a Human en B y C los constructores serian iguales.

PD. Tambien hay bastante codigo de mas en C por el hecho de que un constructor puede lanzar una excepcion, al optimizar llamando solo al operador de asignacion se omite el manejo de excepciones del constructor de B. El constructor de Human no esta inline, sino verias la asignacion de 0x1EC, directamente no es llamado por B.
Efectivamente, tienes razón.
Pero, aunque no se porque, el codigo generado puede ser diferente. Pero no creo que este codigo sea una exepcion. Este codigo es tipico de lo que enseñamos en francia en el sitio developpez.com: respeta el RAII y tal.

He tenido esta informacion aqui:
http: //w w w.parashift.com /c++-faq-lite/ctors.html#faq-10.6
(quitad los espacios, no tengo 30 mensages, asi que no puedo dar un enlace directamente). M. Cline es uno de los mas gurus del c++ moderno y dice eso:
Cita:
In fact, constructors should initialize as a rule all member objects in the initialization list.
traduccion mia:
Cita:
De hecho, los constructores deberian inicializar todos los miembros objetos en la lista de inicializacion. Menos una excepcion[...]
Se puede equivocar, no digo, pero hasta ahora, no hemos visto ningun error en su faq.
  #7 (permalink)  
Antiguo 28/09/2009, 16:43
Avatar de Eternal Idol  
Fecha de Ingreso: mayo-2004
Ubicación: Lucentum
Mensajes: 6.192
Antigüedad: 20 años
Puntos: 74
Respuesta: Que hacen los dos puntos aqui

Cita:
Iniciado por r0d Ver Mensaje
Efectivamente, tienes razón.
Pero, aunque no se porque, el codigo generado puede ser diferente. Este codigo es tipico de lo que enseñamos en francia en el sitio developpez.com: respeta el RAII y tal.
Eso parece aunque no le veo mucha logica a que no pueda optimizar de la misma forma

Cita:
Iniciado por r0d Ver Mensaje
Pero no creo que este codigo sea una exepcion. Este codigo es tipico de lo que enseñamos en francia en el sitio developpez.com: respeta el RAII y tal.
Solamente cuando necesites hacer copia de objetos, mientras tus variables sean primitivas o punteros (a lo que sea) nunca tendras el problema.

De la misma fuente: "Note: There is no performance difference if the type of x_ is some built-in/intrinsic type, such as int or char* or float."
__________________
¡Peron cumple, Evita dignifica! VIVA PERON CARAJO
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 13:09.