Reference vs Pointer in clone idiom

Discussion in 'C++' started by mathieu, Sep 3, 2009.

  1. mathieu

    mathieu Guest

    Hi there,

    Is the following legal (*). I am reading:
    http://www.parashift.com/c -faq-lite/references.html#faq-8.6

    But I am not sure I understand if in my case I should prefer pointer
    over reference since new will throw and I will never dereference a
    NULL pointer.

    Thanks

    (*)
    struct A
    {
    virtual A& clone() { return *new A; }
    };
    struct B : public A
    {
    B& clone() { return *new B; }
    };

    int main()
    {
    A a;
    A &copya = a.clone();

    A * ptra = dynamic_cast<A*>(&copya);
    delete ptra;

    B b;
    A &copyb = b.clone();

    B * ptrb = dynamic_cast<B*>(&copyb);
    delete ptrb;

    return 0;
    }
    mathieu, Sep 3, 2009
    #1
    1. Advertising

  2. mathieu

    mzdude Guest

    On Sep 3, 9:14 am, mathieu <> wrote:
    > Hi there,
    >
    >   Is the following legal (*). I am reading:http://www.parashift.com/c -faq-lite/references.html#faq-8.6
    >
    >   But I am not sure I understand if in my case I should prefer pointer
    > over reference since new will throw and I will never dereference a
    > NULL pointer.
    >


    Prefer pointer to reference. It is a common idiom. Also returning
    a reference totally obscures owenership issues.

    B &b = myObj.clone();
    // absolutely no clue that a delete must be done

    B *b = myObj.clone();
    // Still not sure about deleting, but bears further investigation

    std::auto_ptr<B> b(myObj.clone());
    // Now we're getting somewhere on who owns what
    mzdude, Sep 3, 2009
    #2
    1. Advertising

  3. mathieu

    Noah Roberts Guest

    mathieu wrote:
    > Hi there,
    >
    > Is the following legal (*). I am reading:
    > http://www.parashift.com/c -faq-lite/references.html#faq-8.6
    >
    > But I am not sure I understand if in my case I should prefer pointer
    > over reference since new will throw and I will never dereference a
    > NULL pointer.
    >
    > Thanks
    >
    > (*)
    > struct A
    > {
    > virtual A& clone() { return *new A; }
    > };
    > struct B : public A
    > {
    > B& clone() { return *new B; }
    > };
    >
    > int main()
    > {
    > A a;
    > A &copya = a.clone();
    >
    > A * ptra = dynamic_cast<A*>(&copya);
    > delete ptra;
    >
    > B b;
    > A &copyb = b.clone();
    >
    > B * ptrb = dynamic_cast<B*>(&copyb);
    > delete ptrb;
    >
    > return 0;
    > }


    Yes. Unfortunately all that is legal from what I can see. I have to
    say though, and excuse the blunt nature of this, I'd probably fire
    anyone that wrote anything like this...it's that horrible.
    Noah Roberts, Sep 3, 2009
    #3
  4. On Sep 3, 6:14 am, mathieu <> wrote:
    > Hi there,
    >
    >   Is the following legal (*). I am reading:http://www.parashift.com/c -faq-lite/references.html#faq-8.6
    >
    >   But I am not sure I understand if in my case I should prefer pointer
    > over reference since new will throw and I will never dereference a
    > NULL pointer.
    >
    > Thanks
    >
    > (*)
    > struct A
    > {
    >   virtual A& clone() { return *new A; }};
    >
    > struct B : public A
    > {
    >   B& clone() { return *new B; }
    >
    > };
    >
    > int main()
    > {
    >   A a;
    >   A &copya  = a.clone();
    >
    >   A * ptra = dynamic_cast<A*>(&copya);
    >   delete ptra;
    >
    >   B b;
    >   A &copyb  = b.clone();
    >
    >   B * ptrb = dynamic_cast<B*>(&copyb);
    >   delete ptrb;
    >
    >   return 0;
    > }


    I agree with others when they said prefer pointers over references in
    this case. It's common practice that a returned pointer may be a
    transfer of ownership. A reference almost always is not, because it
    requires the user to get the address to delete it, making it more
    cumbersome.

    Also, question: why have the extra dynamic_cast(s)?

    Don't need one here:
    > A a;
    > A &copya = a.clone();
    > A * ptra = dynamic_cast<A*>(&copya);


    You do need one here because you stored the return result of b.clone
    in a temporary referenced by a A&, and you wanted to cast that to a
    B*.
    > B b;
    > A &copyb = b.clone();
    > B * ptrb = dynamic_cast<B*>(&copyb);
    > delete ptrb;


    However, presumably you will have a virtual destructor in real code,
    so you could do this:
    B b;
    A &copyb = b.clone();
    A* ptra = &copyb;
    delete ptra;

    Sorry, it's just a small question. Just was bugging me. Perhaps you
    were trying to highlight something.
    Joshua Maurice, Sep 4, 2009
    #4
  5. mathieu

    mathieu Guest

    On Sep 4, 9:43 am, Joshua Maurice <> wrote:
    > On Sep 3, 6:14 am, mathieu <> wrote:
    >
    >
    >
    > > Hi there,

    >
    > >   Is the following legal (*). I am reading:http://www.parashift.com/c -faq-lite/references.html#faq-8.6

    >
    > >   But I am not sure I understand if in my case I should prefer pointer
    > > over reference since new will throw and I will never dereference a
    > > NULL pointer.

    >
    > > Thanks

    >
    > > (*)
    > > struct A
    > > {
    > >   virtual A& clone() { return *new A; }};

    >
    > > struct B : public A
    > > {
    > >   B& clone() { return *new B; }

    >
    > > };

    >
    > > int main()
    > > {
    > >   A a;
    > >   A &copya  = a.clone();

    >
    > >   A * ptra = dynamic_cast<A*>(&copya);
    > >   delete ptra;

    >
    > >   B b;
    > >   A &copyb  = b.clone();

    >
    > >   B * ptrb = dynamic_cast<B*>(&copyb);
    > >   delete ptrb;

    >
    > >   return 0;
    > > }

    >
    > I agree with others when they said prefer pointers over references in
    > this case. It's common practice that a returned pointer may be a
    > transfer of ownership. A reference almost always is not, because it
    > requires the user to get the address to delete it, making it more
    > cumbersome.
    >
    > Also, question: why have the extra dynamic_cast(s)?
    >
    > Don't need one here:
    >
    > >   A a;
    > >   A &copya  = a.clone();
    > >   A * ptra = dynamic_cast<A*>(&copya);

    >
    > You do need one here because you stored the return result of b.clone
    > in a temporary referenced by a A&, and you wanted to cast that to a
    > B*.
    >
    > >   B b;
    > >   A &copyb  = b.clone();
    > >   B * ptrb = dynamic_cast<B*>(&copyb);
    > >   delete ptrb;

    >
    > However, presumably you will have a virtual destructor in real code,
    > so you could do this:
    >     B b;
    >     A &copyb  = b.clone();
    >     A* ptra = &copyb;
    >     delete ptra;
    >
    > Sorry, it's just a small question. Just was bugging me. Perhaps you
    > were trying to highlight something.


    When I bumped into that code I claimed that this was illegal (I was
    just very frustrated someone could ever write this kind of thing), but
    after thinking about it... I realized it was legal.
    I simply duplicated the example and did not even realize that I missed
    the virtual destructor :)

    Thanks for pointing that out.
    mathieu, Sep 4, 2009
    #5
  6. mathieu

    James Kanze Guest

    On Sep 3, 9:56 pm, Noah Roberts <> wrote:
    > mathieu wrote:


    > >Is the following legal (*). I am reading:
    > >http://www.parashift.com/c -faq-lite/references.html#faq-8.6


    > > But I am not sure I understand if in my case I should prefer
    > > pointer over reference since new will throw and I will never
    > > dereference a NULL pointer.


    > > (*)
    > > struct A
    > > {
    > > virtual A& clone() { return *new A; }
    > > };
    > > struct B : public A
    > > {
    > > B& clone() { return *new B; }
    > > };


    > > int main()
    > > {
    > > A a;
    > > A &copya = a.clone();


    > > A * ptra = dynamic_cast<A*>(&copya);
    > > delete ptra;


    > > B b;
    > > A &copyb = b.clone();


    > > B * ptrb = dynamic_cast<B*>(&copyb);
    > > delete ptrb;


    > > return 0;
    > > }


    > Yes. Unfortunately all that is legal from what I can see. I
    > have to say though, and excuse the blunt nature of this, I'd
    > probably fire anyone that wrote anything like this...it's that
    > horrible.


    I sort of agree, taking the code globally. But for reasons more
    or less orthogonal to his original question. Something like:

    class A
    {
    public:
    virtual ~A() {}
    virtual A& clone() const { return *new A ; }
    } ;

    class B : public A
    {
    public:
    virtual A& clone() const( return *new B ; }
    } ;

    int
    main()
    {
    A& a = *new A ;
    A& copyA = a.clone() ;
    delete &a ;
    delete &copyA ;

    A& b = *new B ;
    A& copyB = b.clone() ;
    delete &b ;
    delete &copyB ;

    return 0 ;
    }

    might be considered reasonable, IF it conforms to the local
    coding conventions. I've never seen a place which used such
    conventions, however, and I'd argue against such a convention,
    precisely because it is so rare (and thus surprising).
    Everywhere I've worked, or heard of, the convention has been to
    use pointers for intermediate values whenever the final
    operation would require a pointer; i.e. to avoid situations
    which require taking the address of a reference.

    --
    James Kanze
    James Kanze, Sep 5, 2009
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sam pal
    Replies:
    3
    Views:
    527
    E. Robert Tisdale
    Jul 16, 2003
  2. lordy

    To clone or not to clone..

    lordy, Jul 7, 2006, in forum: Java
    Replies:
    3
    Views:
    707
    lordy
    Jul 7, 2006
  3. Belebele

    Dangling Reference. Idiom

    Belebele, Feb 7, 2007, in forum: C++
    Replies:
    10
    Views:
    545
    Grizlyk
    Feb 8, 2007
  4. SG
    Replies:
    4
    Views:
    317
    Bo Persson
    Apr 24, 2010
  5. A
    Replies:
    7
    Views:
    626
Loading...

Share This Page