5

I am trying to define a std::shared_ptr with new operator in the following way:

#include <memory>

struct A {
};

int main() {

  std::shared_ptr<A> ptr = new A();

  return 0;
}

but I obtained the following compile-time error:

main.cpp: In function 'int main()':

main.cpp:8:30: error: conversion from 'A*' to non-scalar type 'std::shared_ptr' requested std::shared_ptr ptr = new A();

Anyway, the following definitely works:

      std::shared_ptr<A> ptr{new A()};

Does anyone of you know why this happens?

2 Answers 2

7

tl;dr: it's a consequence of the relevant constructor being explicit.

When you initialise with =, you invoke copy-initialisation. C++ does not allow copy-initialisation of a shared_ptr from a raw pointer, because it would be too easy to end up with an accidental implicit conversion from some arbitrary raw pointer into a shared_ptr that doesn't actually manage it.

This way, the only way you can "ensnare" a raw pointer into a shared_ptr is very deliberately and very explicitly (as you have correctly done in your second example). Now, only in this initialiser do you have to remember not to do so with a pointer you're already managing elsewhere.

Is there anything actually dangerous about the specific line std::shared_ptr<A> ptr = new A()? No. But what you're seeing is a consequence of various C++ rules working together in concert.

Sign up to request clarification or add additional context in comments.

Comments

5

You can imagine your statement also as a 2 liner like this.

A* a = new A();
std::shared_ptr<A> ptr = a;

While in this case this may be correct in more complicated code it can lead to potential pitfalls so copy initialization is not allowed to a raw pointer.

Imagine

A* a = new A();
//.....
std::shared_ptr<A> ptr = a;
//.....
std::shared_ptr<A> ptr2 = a; //second ptr holding a... UB

Here you would have 2 shared pointers holding the same object which causes trouble.

To avoid those "implicit" errors C++ is not allowing this kind of initialization.

While you can still to the same with constructors but it is more "verbose" and harder to accidentally assign pointers.

std::shared_ptr<A> ptr{ new A() };

This looks more like constructing a new object and may not result in an mis-assignment by accident.

Also the preferred way to create a shared pointer in modern is

auto ptr = std::make_shared<A>();

2 Comments

No, that is not an assignment.
@LightnessRacesinOrbit yeah you are right. I rephrased that part.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.