0

I have a function that returns a shared_ptr to a const object. Returning a shared_ptr constructed from a pointer returned by operator new works, but returning that pointer directly causes compilation error :

Error   3   error C2664: 'std::shared_ptr<_Ty>::shared_ptr(std::nullptr_t)' : cannot convert parameter 1 from 'script::float_data *' to 'std::nullptr_t'    c:\xxx\value.cpp    59

Here is the code causing the error :

shared_ptr< const data > float_data::operator + ( shared_ptr< const data > rhs ) const
{
    int rhs_as_int; float rhs_as_float;

    switch( rhs->to_numeric( rhs_as_int, rhs_as_float ) )
    {
    case E_INT:
        return new float_data( val + rhs_as_int );
    case E_FLOAT:
        return new float_data( val + rhs_as_float );
    }
}

And the classes are :

class data
{
public:

    enum type
    {
        E_INT,
        E_FLOAT,
        E_STRING
    };

public:

    virtual ~data() { }

public:

    virtual std::shared_ptr< const data > operator + ( std::shared_ptr< const data > rhs ) const = 0;

    virtual std::shared_ptr< const data > operator - ( std::shared_ptr< const data > rhs ) const = 0;

    virtual std::shared_ptr< const data > operator * ( std::shared_ptr< const data > rhs ) const = 0;

    virtual std::shared_ptr< const data > operator / ( std::shared_ptr< const data > rhs ) const = 0;

    virtual std::shared_ptr< data > operator = ( std::shared_ptr< const data > rhs ) = 0;

public:

    virtual type to_numeric( int & as_int, float & as_float ) const = 0;
};

class int_data : public data
{
private:

    int val;

public:

    int_data( int i );

public:

    virtual std::shared_ptr< const data > operator + ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator - ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator * ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator / ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< data > operator = ( std::shared_ptr< const data > rhs );

public:

    virtual type to_numeric( int & as_int, float & as_float ) const;
};

class float_data : public data
{
private:

    float val;

public:

    float_data( float f );

public:

    virtual std::shared_ptr< const data > operator + ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator - ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator * ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator / ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< data > operator = ( std::shared_ptr< const data > rhs );

public:

    virtual type to_numeric( int & as_int, float & as_float ) const;
};

class string_data : public data
{
private:

    std::string val;

public:

    string_data( const char * s );

public:

    virtual std::shared_ptr< const data > operator + ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator - ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator * ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< const data > operator / ( std::shared_ptr< const data > rhs ) const;

    virtual std::shared_ptr< data > operator = ( std::shared_ptr< const data > rhs );

public:

    virtual type to_numeric( int & as_int, float & as_float ) const;
};

I don't think this is something specific to C++11, but i'm new to C++11 so i'm not sure. I don't understand why not both ways to return the pointer works and why the compiler automatically chooses the constructor expecting a nullptr_t.

Virus721
  • 8,061
  • 12
  • 67
  • 123

1 Answers1

5

That is because the constructor of std::shared_ptr is explicit, and therefore in the return statement the compiler cannot convert the raw pointer to a std::shared_ptr implicitly when trying to construct the returned object. You must return a std::shared_ptr instead.

You are seeing the strange error because the compiler tries to match the raw pointer parameter to the non-explicit constructor (number 5 here)

constexpr shared_ptr( std::nullptr_t );

Although g++/clang++ are much more helpful in diagnosing the issue, example error:

error: could not convert from 'int*' to 'std::shared_ptr'

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • Okay thanks for your answer. Is there a performance overhead when creating a temporary shared_ptr and returning it ? – Virus721 May 24 '15 at 15:30
  • No overhead, there's RVO, an exception to the as-if-rule. Which on further consideration might be sufficient for this all on its own, though with deeper analysis. – Deduplicator May 24 '15 at 15:30
  • @Virus721 no, not at all, all (decent) compilers perform what's called [return value optimization (RVO)](http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization). – vsoftco May 24 '15 at 15:30