views:

87

answers:

3
class PevSearch
{
    boost::shared_ptr<FilterProvider> filterProvider;
public:
    void RegisterFilter(const boost::shared_ptr<FilterProvider>& toRegister)
    {
        filterProvider = toRegister;
    }
    const boost::shared_ptr<const FilterProvider>& GetFilter() const
    {
        return filterProvider; // Compiler reports "Returning address of local
                               // variable or temporary"
    }
};

I don't see what's local or temporary about filterProvider here. Why would MSVC be reporting this error?

The specific warning is:

warning C4172: returning address of local variable or temporary

Thanks!

Billy3

EDIT: In general, I know what the warning means, but I'm curious where the temporary is coming from here.

+4  A: 

Your shared ptr is declared with type

boost::shared_ptr<FilterProvider>

You are returning

boost::shared_ptr<const FilterProvider>

by const reference. See the difference?

The types are not the same, but the former is convertible to the latter, and the compiler invokes the conversion. The result of the conversion is not an lvalue, but rather a temporary object, meaning that you are returning a const reference bound to a temporary object. This is legal initialization-wise, but the temporary will be destroyed right before the function returns. So in the calling code the reference will be invalid, which is what the compiler is warning you about.

AndreyT
There are multiple correct answers. Checking this one because it was the first posted.
Billy ONeal
+4  A: 

filterProvider is of type boost::shared_ptr<FilterProvider>, but you're returning (a reference to) boost::shared_ptr<const FilterProvider> (note the const). These types are not the same as far as the compiler is concerned. However, an implicit conversion exists. This causes the compiler to make a temporary instead, and you're returning the reference to that temporary, not to the shared_ptr itself.

But why are you handing out a reference to a shared_ptr in the first place? Either hand out a copy of the shared_ptr, or, if you want to prevent modification, hand out a const reference to the underlying FilterProvider object.

Thomas
I want to hand out the object, but it's possible when someone asks that the filter has not yet been set. Therefore calling code needs to be able to get the null reference.
Billy ONeal
So copy the pointer. It's cheap enough.
Pavel Minaev
@Pavel: Then they can modify the target object, which I don't want them to be able to do.
Billy ONeal
Then hand out a `const` pointer :)
Thomas
@Thomas: Oi. Duh! Must be brain fart day.
Billy ONeal
Pavel Minaev
+2  A: 

filterProvider is a shared pointer to a FilterProvider, but GetFilter() returns a reference to a shared pointer to a const FilterProvider.

While, for example, an int can be treated as a const int&, the same does not hold true for templates. A Foo<Bar> is not in any way related to a Foo<const Bar> and so cannot be treated as a Foo<const Bar>&.

Boost provides a conversion from shared_ptr<T> to shared_ptr<const T>, but this conversion involves creating a new temporary object of type shared_ptr<const T>.

So what is happening here is that you are trying to return a shared_ptr<FilterProvider> from a function that wants to return a shared_ptr<const FilterProvider>&. This invokes an explicit conversion which creates a new temporary object of type shared_ptr<const FilterProvider> and then a reference to that is returned. Therefore, you are returning a reference to a temporary.

Tyler McHenry