Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit conversion from int to shared_ptr

Consider the code below:

#include <iostream>
#include <memory>

void f(std::shared_ptr<int> sp) {}

template <typename FuncType, typename PtrType>
auto call_f(FuncType f, PtrType p) -> decltype(f(p))
{
    return f(p);
}

int main()
{
    f(0); // doesn't work for any other int != 0, thanks @Rupesh
    // call_f(f, 0); // error, cannot convert int to shared_ptr
}

In the first line in main(), the integer 0 is converted to a std::shared_ptr<int> and the call f(0) succeeds without any problem. However, using a template to call the function make things different. Second line will not compile anymore, the error being

error: could not convert 'p' from 'int' to 'std::shared_ptr<int>'

My questions are:

  1. Why does the first call succeed and the second doesn't? Is there anything I'm missing here?
  2. I don't understand also how the conversion from int to std::shared_ptr is being performed in the call f(0), as it looks like std::shared_ptr has only explicit constructors.

PS: A variant of this example appears in Scott Meyers' Effective Modern C++ Item 8, as a way of protecting such calls with nullptr.

like image 297
vsoftco Avatar asked Feb 18 '15 16:02

vsoftco


People also ask

What is the purpose of the shared_ptr <> template?

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object.

Can you convert shared_ptr to Unique_ptr?

In short, you can easily and efficiently convert a std::unique_ptr to std::shared_ptr but you cannot convert std::shared_ptr to std::unique_ptr .

What is shared_ptr?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.

Is shared_ptr slow?

When we create an object with new operator in shared_ptr there will be two dynamic memory allocations that happen, one for object from the new and the second is the manager object created by the shared_ptr constructor. Since memory allocations are slow, creating shared_ptr is slow when compared to raw pointer.


1 Answers

std::shared_ptr has a constructor that takes std::nullptr_t, literal 0 is a null pointer constant that is convertiable to std::nullptr_t from the draft C++ standard section 4.10 [conv.ptr] (emphasis mine going forward):

A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. —end note ]

in your second case p is being deduced as type int which although has the value zero is no longer a null pointer constant and so does not fit the same case.

As T.C. points out the wording was changed with DR 903 which requires an integer literal with value zero as opposed to an integral constant expression which evaluates to zero:

A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.

like image 162
Shafik Yaghmour Avatar answered Sep 22 '22 17:09

Shafik Yaghmour