Toon posts:

[C++] Reference-initialisatie d.m.v. conditional operator

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter

Afgesplitst van De Devschuur Coffee Corner - Iteratie 3

Is de ?: operator echt de enige manier om conditioneel een reference te initialiseren?

C++:
1
2
3
4
5
6
int& foo;

if ( boolean )
  foo = bar;
else
  foo = baz;


Werkt niet omdat: een reference dient altijd geïnitialiseerd te zijn.

Wat dacht je dan van

C++:
1
2
3
4
if ( boolean )
  int& foo = bar;
else
  int& foo = baz;

Nee, dat werkt ook niet. Want na de if raakt foo uit scope..

Mag ik u voorstellen aan deze oude vriend?
C++:
1
2
3
4
5
6
7
8
9
10
if ( boolean )
  goto next;

  int& foo = baz;
  goto finish;

next:
  int& foo = bar;

finish:


Foo already initialized. Je meent het?

Dan maar zo:
C++:
1
int& foo = boolean ? bar : baz;


al is dat bij ingewikkeldere constructs natuurlijk totaal onleesbaar.

[ Voor 5% gewijzigd door Woy op 13-05-2013 11:06 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op zaterdag 11 mei 2013 @ 23:36:
Is de ?: operator echt de enige manier om conditioneel een reference te initialiseren?
Sterker nog, dat is de reden dat hij bestaat. Niet specifiek voor references, maar wel initialization van objects waar een expression vereist is.

Imho schiet C++ daar wel wat te kort. Probeer maar eens een value te constructen waarvan de gewenste ctor overload afhangt van een expressie.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Verwijderd schreef op zaterdag 11 mei 2013 @ 23:36:

al is dat bij ingewikkeldere constructs natuurlijk totaal onleesbaar.
Je zou nog een init_ref<T> functie kunnen maken die 't doet, maar dat is ook niet heel anders dan een ?:-constructie. Gewoon netjes opschrijven;

C++:
1
2
3
T &ref = lijpe_conditional
    ? expression_1
    : expression_2;

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Of gewoon met pointers werken:
C++:
1
2
3
4
5
6
int* foo; 

if ( boolean ) 
  foo = &bar; 
else 
  foo = &baz;


als je de waarde nodig hebt gebruik je *foo.

Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Daos schreef op zondag 12 mei 2013 @ 12:32:
Of gewoon met pointers werken:
C++:
1
2
3
4
5
6
int* foo; 

if ( boolean ) 
  foo = &bar; 
else 
  foo = &baz;


als je de waarde nodig hebt gebruik je *foo.
Dat wil je niet altijd :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Het zal, i guess, over het algemeen wel naar dezelfde code compileren.

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Verwijderd schreef op zondag 12 mei 2013 @ 18:22:
Het zal, i guess, over het algemeen wel naar dezelfde code compileren.
Daar lijkt het wel op (refptr.cpp):
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

int test_ref(bool boolean) {
    int bar = 5;
    int baz = 10;

    int& foo = boolean ? bar : baz;
    
    return foo;
}

int test_ptr(bool boolean) {
    int bar = 5;
    int baz = 10;

    int* foo = boolean ? &bar : &baz;
    
    return *foo;
}

int main(void) {
    std::cout << test_ref(true) << std::endl;
    std::cout << test_ref(false) << std::endl;
    std::cout << test_ptr(true) << std::endl;
    std::cout << test_ptr(false) << std::endl;
}


Assembly van de twee functies is identiek (g++ refptr.cpp -S):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.globl __Z8test_refb
    .def    __Z8test_refb;  .scl    2;  .type   32; .endef
__Z8test_refb:
LFB963:
    pushl   %ebp
LCFI0:
    movl    %esp, %ebp
LCFI1:
    subl    $20, %esp
LCFI2:
    movl    8(%ebp), %eax
    movb    %al, -20(%ebp)
    movl    $5, -8(%ebp)
    movl    $10, -12(%ebp)
    cmpb    $0, -20(%ebp)
    je  L2
    leal    -8(%ebp), %eax
    jmp L3
L2:
    leal    -12(%ebp), %eax
L3:
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    movl    (%eax), %eax
    leave
LCFI3:
    ret
LFE963:
.globl __Z8test_ptrb
    .def    __Z8test_ptrb;  .scl    2;  .type   32; .endef
__Z8test_ptrb:
LFB964:
    pushl   %ebp
LCFI4:
    movl    %esp, %ebp
LCFI5:
    subl    $20, %esp
LCFI6:
    movl    8(%ebp), %eax
    movb    %al, -20(%ebp)
    movl    $5, -8(%ebp)
    movl    $10, -12(%ebp)
    cmpb    $0, -20(%ebp)
    je  L5
    leal    -8(%ebp), %eax
    jmp L6
L5:
    leal    -12(%ebp), %eax
L6:
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    movl    (%eax), %eax
    leave
LCFI7:
    ret

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Verwijderd schreef op zaterdag 11 mei 2013 @ 23:36:
Werkt niet omdat: een reference dient altijd geïnitialiseerd te zijn.
Kun je hem niet op null initialiseren?

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Grijze Vos schreef op maandag 13 mei 2013 @ 10:15:
[...]

Kun je hem niet op null initialiseren?
Je kan een reference niet naar een NULL object laten wijzen (ja, met pointer magic). Maar daar schiet je alsnog niets mee op, want je kan een reference niet re-assignen.

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Verwijderd schreef op maandag 13 mei 2013 @ 10:24:
[...]

Je kan een reference niet naar een NULL object laten wijzen (ja, met pointer magic). Maar daar schiet je alsnog niets mee op, want je kan een reference niet re-assignen.
Hmm, ik zie maar weer dat mijn kennis van C++ heel beperkt is. :) Ik wist niet dat een reference niet ge-re-seat kon worden.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 01:10
Grijze Vos schreef op maandag 13 mei 2013 @ 10:37:
[...] Hmm, ik zie maar weer dat mijn kennis van C++ heel beperkt is. :) Ik wist niet dat een reference niet ge-re-seat kon worden.
Een reference is (correct me if I'm wrong) gewoon een alias. Een andere naam voor hetzelfde object. Kan me ook goed voorstellen dat de compiler het een en ander gewoon weggooit, omdat een verwijzing naar de reference eigenlijk een verwijzing naar het object dat gereferenced wordt is.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Caelorum schreef op maandag 13 mei 2013 @ 10:44:
[...]

Een reference is (correct me if I'm wrong) gewoon een alias. Een andere naam voor hetzelfde object. Kan me ook goed voorstellen dat de compiler het een en ander gewoon weggooit, omdat een verwijzing naar de reference eigenlijk een verwijzing naar het object dat gereferenced wordt is.
Een reference is gewoon een const pointer (niet te verwarren met pointer-naar-const) met ietwat andere syntax, meer niet.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • epic007
  • Registratie: Februari 2004
  • Laatst online: 07-10 10:46
Daos schreef op zondag 12 mei 2013 @ 12:32:
Of gewoon met pointers werken:
C++:
1
2
3
4
5
6
int* foo; 

if ( boolean ) 
  foo = &bar; 
else 
  foo = &baz;


als je de waarde nodig hebt gebruik je *foo.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
int& give_me_an_int_ref(bool boolean)
{
  int* pfoo; 

  if ( boolean ) 
    pfoo = &bar; 
  else 
    pfoo = &baz;

  return *pfoo;
}

int& foo =  give_me_an_int_ref(boolean);

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dat is ook weer scope vervuiling ;)

Ik bedenk met overigens net dat het ook met een lambda functie kan:

C++:
1
2
3
4
5
6
int &foo = [&,bar,baz,boolean](){
  if ( boolean ) 
    return bar; 
  else 
    return baz; 
}();

(untested)

Wat waarschijnlijk de netste manier is voor wat ingewikkeldere constructies.

Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 01:10
.oisyn schreef op maandag 13 mei 2013 @ 11:06:
[...] Een reference is gewoon een const pointer (niet te verwarren met pointer-naar-const) met ietwat andere syntax, meer niet.
en een const reference is dan een const-pointer-naar-const?

@onder: ah ik zie het al: http://www.parashift.com/c++-faq-lite/const-ref-alt.html
const X& x and X const& x are equivalent. The real question is which should be used.

[ Voor 24% gewijzigd door Caelorum op 14-05-2013 13:33 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Als je bedoelt een reference-naar-const, dan ja. Const references (int & const i) bestaan niet (of ze zijn impliciet const)

[ Voor 10% gewijzigd door .oisyn op 14-05-2013 12:46 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Vraag is hoe vaak je dit nodig hebt. Meestal zal het toch een functie zijn die dan beslists welke je gebruikt; zeker als het een ingewikkelde conditional is. En daar kan je gewoon returnen, net als bij het lambda voorbeeld.

?operator is overigens ook de enige manier om bijvoorbeeld een constexpr met een conditional te hebben (constexpr int max(int a, int b) {return a < b ? b : a;})

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Niet helemaal waar: constexpr int max(int a, int b) {return a + int(b>a) * (b-a); }

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1