views:

146

answers:

6

I recently reworked one of my own libraries to try out separating interface from implementation. I am having on final issue with a class that is meant to return an instance of another class.

In the interface definition, I do something like

struct IFoo
{
    virtual const IBar& getBar() = 0;
}

and then in the concrete Foo getBar looks like

const IBar& Foo::getBar()
{
    Bar ret = Bar();
    return ret;
}

The problem is ret gets deleted as soon as getBar is done, causing a big crash when the copy constructor tries to use Bar like so

const Bar myBar = myFoo.getBar();

I have been reading various things, and I know returning by reference is frowned upon, but I do not see any other way (I do not want to return Bar* because I do not want to have to manually delete the return value).

What is the proper way (if any way exists) for an abstract class to return an instance of a concrete class derived from another abstract class?

Note I did see this solution: http://stackoverflow.com/questions/2861270/returning-an-abstract-class-from-a-function but I do not want to make the return value static and loose thread safety.

+2  A: 

You're returning a reference to a local variable. As soon as the function returns the reference, the stack gets popped and that Bar object ceases to exist.

EDIT: I didn't read the whole thing. You'll probably need to use a smart pointer.

Actually, is there any reason why you need to return a base class reference? You could avoid any smart pointer messiness by returning an object of the concrete type itself, since C++ allows covariant return types.

Adrian
Charles
@Adrian I think the covariance of function return types works only when returning object references and pointers.
Alexandre Jasmin
+8  A: 

Use smart pointers. These are pointers deleted when not used anymore (see for example http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/smart_ptr.htm).

Scharron
smart pointers! that is a really good idea!
Charles
a ... smart idea ? ;-)
Scharron
haha, returning a smart pointer makes using the return type a bit more difficult, but I think this should work out nicely, thanks.
Charles
I think that you should consider using smart pointers the correct way before using them all over the place. This blog is an interesting read regarding the topic and how they are easily overused: http://www.bureau14.fr/blogea/index.php/2009/08/smart-pointers-are-overused/
Simon
Charles
+1  A: 

Since you want to transfer ownership of the returned object to the caller, the caller will have to destroy the object. In other words, returning IBar * is your best bet. If you are worried about having to manually call delete, you should look into using a smart pointer package, e.g. boost::shared_ptr.

Anatoly Fayngelerin
I think it seems like he doesn't want to transfer ownership since he doesn't want to delete the instance himself. If you don't want to delete it, you shouldn't take ownership of it. (Even if it is a smart-pointer).
Simon
So there are two potential interpretations of the original question:1) The author is worried that the caller will have to call delete(e.g. ownership is transfered)2) The author is worried that the class itself will have to call delete. This would mean that a pointer is stored as a member of the class. However, if this is true, than what's stopping the author from making the instance a member of the class and returning a reference?That was my reasoning behind assuming that ownership was supposed to be transferred.
Anatoly Fayngelerin
+1  A: 

If you don't want to take care of deletion then you have to use SmartPointers. In C++ this is the only way to have object "deletes itself" when it is appropriated.

http://en.wikipedia.org/wiki/Smart_pointer

Moisei
+1  A: 
Simon
+3  A: 

You can also return the object by value.

Some compilers provide the Return value optimization which optimize away the copy when returning an object.

Edit:
Sorry. I skimmed through the question and somehow missed the fact that inheritance is involved. Assuming that getBar() can return various kind of IBar returning an IBar pointer makes a lot of sense.

By returning a pointer to base the concrete object is kept intact. The slicing problem is avoided and the original vtbl pointer is available to make virtual function calls. Also (as you noted in your comment) returning an instance of an abstract class is just impossible.

Instead of returning a raw pointer I suggest you return a shared_ptr<IBar> to simplify memory management.

const shared_ptr<IBar> Foo::getBar()
{
    shared_ptr<IBar> ret(new Bar());
    return ret;
}

Then use it this way:

shared_ptr<IBar> pIBar(foo.getBar());
pIBar->myVirtualFunction();

shared_ptr is the most commonly used smart pointer type in C++0x. If you have a sufficiently recent compiler it will be in the std namespace. Older compiler may have it in the tr1 namespace and it's also part of boost.

Alexandre Jasmin
Charles