0

This might be regarded as a style question. I have a class that keeps a reference to an instance of another class:

class A { };

class B {
  A& ref;

public:
  explicit B(A& ref) : A(ref) { }
};

I decided to use references instead of pointers, because ref could never be a null pointer. Also, the code looks nicer.

But, the user has no idea whether I copy A or not right? In this case, I don't copy, so if A is destroyed while an instance of B is still existing, problems will happen. If you use pointers, then of course the same can happen, but I feel that the user is then aware, as he writes the code, that no copying is being done.

Opinions about this? What would be the best C++ way to deal with this problem?

PS.: One solution I thought of is to make things so that a pointer is kept, but if the object it points to is destroyed, then a copy is made first. This is not so difficult to implement, but the point is: would the extra trouble be worth it and would the overhead justify it? Is this sort of self-made reference counter something that people do really?

Fernando
  • 595
  • 1
  • 3
  • 12
  • If you need to retain something for the objects life-span, copy it. – StoryTeller - Unslander Monica May 21 '13 at 09:51
  • 2
    You don't need to self-make a reference counter. Use `std::unique_ptr`, or `std::shared_ptr`. – Peter Wood May 21 '13 at 09:54
  • 1
    @StoryTeller: in computation-heavy scientific applications, it is not always wise to copy (sometimes very very big) things, unless you absolutely need to do so. :) – Fernando May 21 '13 at 09:56
  • You didn't specify the background of your problem. Regardless, Peter gave you a good solution. If you don't have c++11, those smart pointer class can be download with/from boost. – StoryTeller - Unslander Monica May 21 '13 at 09:58
  • @StoryTeller Just adding on, for older versions those classes might be available under the std::tr1 namespace. – dutt May 21 '13 at 10:02
  • One important difference is that the reference member makes the class unassignable, while a pointer member doesn't. You may or may not want that. – Mike Seymour May 21 '13 at 10:31
  • Don't assume the reference is never NULL, it can be NULL. – UltimaWeapon May 21 '13 at 11:43
  • C: None of the above. Use `shared_ptr` – John Dibling May 21 '13 at 14:13
  • @PeterWood Make a pointer of `A` and set it to NULL. Then, construct `B` and dereference the pointer of `A` and pass it to constructor. Now, you got NULL for `ref` in B class. – UltimaWeapon May 22 '13 at 07:03
  • @Putta No, [dereferencing a null pointer produces undefined behaviour](http://stackoverflow.com/questions/2165078/a-reference-can-not-be-null-or-it-can-be-null), not a null reference. – Peter Wood May 22 '13 at 07:26
  • @PeterWood You can try it by get the address of `ref` in the `B` class, like this `A *p = &ref;`. `p` will be alway NULL. – UltimaWeapon May 22 '13 at 07:30
  • @Putta On which compiler? This is undefined behaviour. It could do what you think it should on your compiler, but any other compiler (or compiler options), could cause it to behave completely differently. Unfortunately for you it isn't crashing. – Peter Wood May 22 '13 at 07:34
  • @PeterWood Crashing should be happenned if you dereferences `A` and access it members. But, if you construct `B` with `B(*p)`, it not crashing on that line. I'm testing it on Visual C++. But, other compiler should be produces the same result because reference is implemented by using the address of variable to references, like pointer. In other word, the references is just a pointer. – UltimaWeapon May 22 '13 at 07:44
  • @Putta You're making too many assumptions. Don't let Visual C++ teach you C++. Just because it behaves in a particular way, doesn't mean you're correct. It is undefined behaviour, but for a given implementation it makes sense that the undefined behaviour will behave in a particular way. But don't take 'making sense' to mean 'correct behaviour'. For different implementations, if it crashes you would say, 'that makes sense', or if it fires up DooM and performs a speedrun of E3M7 you'd say, 'that's surprising, but it makes sense because...' It's all implementation details. Don't let it fool you. – Peter Wood May 22 '13 at 08:02
  • @PeterWood I'm already known that. My first comment is "Don't assume the reference is never NULL, it can be NULL.". That mean it can be NULL in some compilers. So, don't trust only C++ specification. – UltimaWeapon May 22 '13 at 08:11
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/30385/discussion-between-peter-wood-and-putta-khunchalee) – Peter Wood May 22 '13 at 08:15

4 Answers4

3

If B must only ever use a single instance of A and that instance will never change, a reference makes sense. Thus, B cannot be constructed without an instance of A - you introduce a tight coupling.

However, if you can have an instance of B independently of A, then make it a pointer - which will allow you to set the instance of A later as needed. Eitherway, you have to guarantee the lifetime of A; the only way to avoid this(life time control) is to use a smart pointer to manage the life time of A.

Nim
  • 33,299
  • 2
  • 62
  • 101
1

I have a class that keeps a reference to an instance of another class:

Because your class does not have private assignment operator, it is supposed to be copyable and assigneable, so either your decision is an error (and you should've used pointer), or your class declaration is incomplete. Also see rule of three.

If your class is going to have assignment operator (operator=), you'll have to use pointer or some kind of smart pointer (like std::weak_ptr).

In general, it makes sense to use following rules:

  1. In function parameters, if parameter is "big" or have expensive copy constructor, use either referneces or pointers.
  2. If if that parameter is optional and can be 0/NULL/null_ptr, use pointers, otherwise use references.
  3. For local variables that "point" at something, use references, unless the value of that variable can change.
  4. When you need to point at "something" and have to use pointers, use standard pointers if you don't manage that object's lifetime, and smart pointers (std::shared_ptr and such) otherwise.
  5. You should never call delete yourself, unless your code is constrained and you have to avoid using both stl and boost . Memory mangement should be performed authomatically when possible. That reduces chance of error.
  6. In class members, use references only if that class cannot be copied in any way (singleton, for example).
SigTerm
  • 26,089
  • 6
  • 66
  • 115
0

generally speaking, it is exactly the same, with both pointers and references...

you are saying that it is possible to delete the object A referenced in B, and therefore it is valid to have a B object with no A referenced object. You can't do this with references, you need null pointers -> use pointer, not reference

Exceptyon
  • 1,584
  • 16
  • 23
0

This is my personal rule - reference for function parameters that won't persist, pointers for things that do persist. Then if the user passes by pointer, he needs look closer at the lifespan. Also, what happens if you want to copy B's? If it's a reference, you can't change it any more.

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91