Dear Ralph McArdell,
I have 4 seemingly similar questions about reference:
1. Can you return a reference to public data member?
2. Can you return a reference to private data member?
3. Can you return a reference to auto object?
4. Can you return a reference to static object or data member?
I feel so confused about these questions, which I got from a C++ interview Question collection. Can you make them a little bit specific?
Thanks a lot,
The word in all these questions that we should focus on here is 'can'. C++ does not prevent you doing too many silly things. Thus the answer to all these questions is:
Yes, we can, the compiler is not going to stop us.
However just because the language allows us to do something does not mean that doing so is a good idea. Hence while the answer to all these questions is: Yes we can, maybe a better question to ask is
Should we be doing so?
There are two possible reasons why we may not want to: it leads to erroneous code that will likely fail or the code produced will work but there is some failure of design.
The first question's case leads to the question: why bother? You can access the data member directly as it is public. It also leads to the question: Why are the data members public? Class and object data should be considered an implementation detail and so should be private.
The second question's case seems quite reasonable. However it breaks encapsulation as returning a non-const reference to a private data member from a public member function in effect makes the data member public as you can do anything to the data member through the returned reference. If the returned reference were const (and hopefully the member function were also const) then at least users could only access the private data member for reading (at least without resorting to using type casting, such as a const_cast - which hopefully will throw up a red flag to anyone reading the code that something dodgy may be going on).
The third question would be a case in which the code would likely fail when run. This is because auto objects _only_ exist (at maximum) for the duration of a function call to the function in which they are defined. Thus returning a reference to such an object, like returning a pointer to an auto object, leads to a reference to an object that has been destroyed. OK, in some cases you might get away with it - if you assign the returned reference to an object immediately and it has a trivial (do nothing) destructor then maybe the auto object still exists - or at least its memory has not been overwritten yet. But in general returning references or pointers to automatic local object is a no no.
The forth question's case is also interesting. It does not specify the context in which we would be returning a reference to such an object or data member. If the object was at global scope or a class static data member was public then this is a variation on the first question: Why bother? Why are we using global data? Why are (static) data members public? Etc. If returned for an instance member function then why are we returning static data from a class-instance member function? Why is the function not a static member function? If returned from a public static function that referred to a private static data member then we are in a question 2 situation!
However if the function defined a local static object then there is a very good reason we might wish to return a reference to it. As the object is static it will exist from (effectively) the first time the code execution path encounters the object definition until the end of the program, hence returning a reference to it will be safe in that the object referred to will still exist after returning from a function call. Further, because the point of construction (as mentioned above) is well defined whereas the order of construction of global static objects is not defined when they are defined in different translation units (compiled source files), making such objects local static objects can solve problems with fragile global(static) object orders of construction. For a fuller explanation see Scott Meyer's excellent book "Effective C++" "Item 47: Ensure that non-local static objects are initialized before they're used" (I checked the 2nd edition, so other editions may vary slightly in what items are where etc.).
One thing about static data is that it is _not_ thread safe. Because a whole program shares the single instance of each static object, different threads can access the same object at the same time. This is OK if multiple threads are just reading the data, but if one or more threads are reading while another is updating or more than one thread is updating a static object at the same time chaos ensues. Note that several of the old C library functions, such as strtok, rely on static data internally and thus are not thread safe.
Hope this helps.