Learning C++: returning references AND getting around slicing

In order to avoid slicing you have to return or pass around a pointer to the object. (Note that a reference is basically a 'permanently dereferenced pointer'.

Animal r2 = rFunc();
r2.makeSound();

Here, r2 is ting instantiated (using the compiler generated copy ctor) but it's leaving off the Dog parts. If you do it like this the slicing won't occur:

Animal& r2 = rFunc();

However your vFunc() function slices inside the method itself.

I'll also mention this function:

Animal& rFunc()
{
    return *(new Dog());
}

It's weird and unsafe; you're creating a reference to a temporary unnamed variable (dereferenced Dog). It's more appropriate to return the pointer. Returning references is normally used to return member variables and so on.


To answer the second part of your question ("how do I communicate that the pointer is subject to deletion at any time") -

This is a dangerous practice, and has subtle details you will need to consider. It is racy in nature.

If the pointer can be deleted at any point in time, it is never safe to use it from another context, because even if you check "are you still valid?" every time, it may be deleted just a tiny bit after the check, but before you get to use it.

A safe way to do these things is the "weak pointer" concept - have the object be stored as a shared pointer (one level of indirection, can be released at any time), and have the returned value be a weak pointer - something that you must query before you can use, and must release after you've used it. This way as long the object is still valid, you can use it.

Pseudo code (based on invented weak and shared pointers, I'm not using Boost...) -

weak< Animal > animalWeak = getAnimalThatMayDisappear();
// ...
{
    shared< Animal > animal = animalWeak.getShared();
    if ( animal )
    {
        // 'animal' is still valid, use it.
        // ...
    }
    else
    {
        // 'animal' is not valid, can't use it. It points to NULL.
        // Now what?
    }
}
// And at this point the shared pointer of 'animal' is implicitly released.

But this is complex and error prone, and would likely make your life harder. I'd recommend going for simpler designs if possible.


1) If you're creating new objects, you never want to return a reference (see your own comment on #3.) You can return a pointer (possibly wrapped by std::shared_ptr or std::auto_ptr). (You could also return by copy, but this is incompatible with using the new operator; it's also slightly incompatible with polymorphism.)

2) rFunc is just wrong. Don't do that. If you used new to create the object, then return it through an (optionally wrapped) pointer.

3) You're not supposed to. That is what pointers are for.


EDIT (responding to your update:) It's hard to picture the scenario you're describing. Would it be more accurate to say that the returned pointer may be invalid once the caller makes a call to some other (specific) method?

I'd advise against using such a model, but if you absolutely must do this, and you must enforce this in your API, then you probably need to add a level of indirection, or even two. Example: Wrap the real object in a reference-counted object which contains the real pointer. The reference-counted object's pointer is set to null when the real object is deleted. This is ugly. (There may be better ways to do it, but they may still be ugly.)