Reference vs Pointer in clone idiom

M

mathieu

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;
}
 
M

mzdude

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
 
N

Noah Roberts

mathieu said:
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.
 
J

Joshua Maurice

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.
 
M

mathieu

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:


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*.


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.
 
J

James Kanze

mathieu wrote:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top