views:

919

answers:

4

In C++, is it safe to extend scope via a reference?

In code, what I mean is:

MyCLass& function badIdea()
{
    MyClass obj1;
    ...
    return obj1;
}
A: 

Please clarify what you do mean.

Assuming you intend to do this:

int * p = NULL;
{
  int y = 22;
  p = &y;
}
*p = 77; // BOOM!

Then no, absolutely not, scope does not get extended by having a reference.

You may want to look at smart pointers, e.g. from boost libraries: clickety

peterchen
I meant references, not pointers
Brian R. Bondy
references act the same as pointers, only they can't be re-bound
peterchen
+16  A: 

It is NOT safe to extend the scope via reference. Objects in C are not reference counted when obj1 goes out of scope it will be deleted, refering to the result of badIdea() will only get you into trouble

Harald Scheirich
The question was about C++ and reference binding. Reference counting does not enter into it. I've added an answer of my own, but briefly, you *can* extend the scope of an object by reference binding but should be careful in your design. Don't do it if you don't understand it.
Don Wakefield
I think he referred to reference counting since that is how you *could* return a reference without the local object going out of scope in languages that support reference counting (C++ not being one of them, of course).
Jim Buck
I can see how the term "reference counting" muddies the issues, i was trying to hint to mechanisms that other languages have that might keep allocated objects alive, maybe not a good idea
Harald Scheirich
+7  A: 

The only place it's OK to extend a scope with a reference is with a const reference in namespace or function scope (not with class members).

const int & cir = 1+1; // OK to use cir = 2 after this line

This trick is used in Andrei Alexandrescu's very cool scope guard in order to capture a const reference to a base class of the concrete scope guard.

Motti
Note this is only "extending the scope" in the sense the the usually very narrow "scope" of a temporary is extended to the parent scope, which is quite different to what the OP was asking. Kudos for mentioning a little known aspect of C++ that a lot of people are confused by at first.
Phil Nash
A: 

It can be dangerous or useful, depending on your design. Be careful.

A Dangerous Usage (Don't Do This)

class Example
{
public:
   Example(A *a) : a_p(a) {};
   ~Example() {};
private:
   A *a_p;
};

const Example &dangerous()
{
   A object_a;
   Example object_e(&a);
   return object_e;
}

// elsewhere in another translation unit...
const Example &e = dangerous();

The final line binds the Example object created within dangerous() so that it's destructor is not called. This is okay and can be applied in a careful design (for instance, supplying a Strategy object as an initialization argument to a constructor).

Emphasis: The problem here is that Example has a pointer data member, which is initialized to point to data that is local to dangerous()'s stack, and goes away once we return from dangerous().

A Useful Usage (Apply with Care)

Here is a simplistic example showing how to use const references to attach a default policy to a class constructor:

class BasePolicy
{
   // Derive to affect policy, but prefer no data members
public:
   BasePolicy() {};
   virtual ~BasePolicy() {};

   virtual bool serialize_as_binary() { return true; }
};

class DataObject
{
public:
   DataObject(const BasePolicy &bp = BasePolicy()) : policy_d(bp) {};
   ~DataObject() {};
private:
   const BasePolicy &policy_d;
};

// elsewhere in another translation unit...
const XmlPolicy &xp = get_xml_policy(); // derived from BasePolicy;

DataObject do(xp);

Here, the reference binds to the data member, and will live as long as do does, regardless of whether the policy object is the supplied default, or an 'outside' object as in the example.

Don Wakefield
This has the exact same problem as the OP's example. You are returning a pointer (a_p) to a stack address that is not valid once the function exits.
Jim Buck
I took your comment into consideration and beefed up my answer to clarify that the original example was the negative one, and included a positive one as well.
Don Wakefield