6

Given a class "A" exists and is correct. What would be some of the negative results of using a reference to "A" instead of a pointer in a class "B". That is:

// In Declaration File
class A;

class B
{
public:
   B();
   ~B();
private:
    A& a;
};

// In Definition File
B::B(): a(* new A())
{}

B::~B()
{
    delete &a;
}

Omitted extra code for further correctness of "B", such as the copy constructor and assignment operator, just wanted to demonstrate the concept of the question.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
JadziaMD
  • 2,690
  • 5
  • 31
  • 42
  • 1
    Interesting. I haven's seen such code before. May be, this is just a way to avoid dereferencing and using `->` and still making `a` dynamically allocated, for some reason :? +1 for the question. – Kiril Kirov Nov 09 '11 at 20:22
  • What's the point of this, instead of just `A a;`? Wouldn't that be better than both references or pointers? – tenfour Nov 09 '11 at 20:23
  • 1
    @tenfour in many cases, but it's a simplified example - assume that the value behind `a` is created by a factory. – justin Nov 09 '11 at 20:29
  • 2
    @tenfour Also using a value object prevents forward declarations. – JadziaMD Nov 09 '11 at 21:07
  • Initializing a reference with a dereferenced pointer obtained by `new` is not idiomatic C++. – fredoverflow Nov 09 '11 at 22:55

6 Answers6

4

The immediate limitations are that:

  • You cannot alter a reference's value. You can alter the A it refers to, but you cannot reallocate or reassign a during B's lifetime.
  • a must never be 0.

Thus:

  • The object is not assignable.
  • B should not be copy constructible, unless you teach A and its subtypes to clone properly.
  • B will not be a good candidate as an element of collections types if stored as value. A vector of Bs would likely be implemented most easily as std::vector<B*>, which may introduce further complications (or simplifications, depending on your design).

These may be good things, depending on your needs.

Caveats:

  • slicing is another problem to be aware of if a is assignable and assignment is reachable within B.
justin
  • 104,054
  • 14
  • 179
  • 226
  • 1
    +1 for "these may be good things"... which is what I think they are (assuming they're applicable). Using a reference instead of a pointer where possible documents the fact it's not null and won't change... very useful information when trying to make sense of someone else's code. – timday Nov 09 '11 at 20:32
  • Edited to reflect that the missing code was the copy constructor and assignment operator. – JadziaMD Nov 09 '11 at 21:05
  • 1
    That first "drawback" is _a very, very, good thing_, and the second just extends it. That `B` will no longer be assignable is also good, because it's better than `B` being assignable in a broken way. – Lightness Races in Orbit Nov 09 '11 at 21:07
  • @timday: It also stops you from introducing dynamic object lifetime bugs... to some extent. – Lightness Races in Orbit Nov 09 '11 at 21:08
  • It's absolutely a good thing for some problems. One common use I have made from it is when moving reference counted objects (in that case, `A` is a reference counted type and `B` is just a container which holds a reference). – justin Nov 09 '11 at 21:41
  • Maybe "immediate limitations" would be a less biased way of describing them than "immediate drawbacks"! – timday Nov 10 '11 at 00:00
2

You can't change the object referred to by a after the fact, e.g. on assignment. Also, it makes your type non-POD (the type given would be non-POD anyway due to the private data member anyway, but in some cases it might matter).

But the main disadvantage is probably it might confuse readers of your code.

celtschk
  • 19,311
  • 3
  • 39
  • 64
1

The problem with references is that it looks like a alias or other name for same variable but it you look at the machine code generated internally they use constant pointers to do operations, and this can be a performance issue because you may assume within a code that variable arithmetic is taking place but at assembly code level they are manipulating pointers which you may not realize at code level. You may not want to use pointer manipulation where you want fast integer or float arithmetic.

1

Of course, by adding a reference member to your class B means that the compiler can no longer generate the implicit default and copy constructors, and assignment operators; and neither a manually written assignment operator can reasign a.

I don't think there are negative results, other than the fact that delete &a may look odd. The fact that the object was created by new is somewhat lost by binding the result to a reference, and it may only matter since the fact that its lifetime has to be controlled by B is not clear.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
1

If you use a reference:

  • You must provide the value at construction time
  • You cannot change what it refers to
  • It cannot be null
  • It will prevent your class from being assignable

You might perhaps consider using a smart pointer of some sort instead (std::unique_ptr, std::shared_ptr, etc). This has the added benefit of automatically deleting the object for you.

0

A reference to a dynamically-allocated object violates the principle of least surprise; that is, no one normally expects code written as you have. In general that will make the maintenance cost higher in the future.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Mark B
  • 95,107
  • 10
  • 109
  • 188