3

I understand:

shared_ptr<X> x = make_shared<X>();

is more efficient than:

shared_ptr<X> x(new X());

and I understand the advantages. However, I do not understand why the compiler could not have a rule like

"if I see new() in the same line as a shared_ptr declaration, use make_shared"

So what is it which stops compilers from automatically using make_shared and instead requiring us to specify it?

user3811839
  • 141
  • 7
  • 2
    It's not about efficiency, it's about exception-safety. – user657267 Jul 28 '14 at 09:00
  • 2
    The efficiency gains from `make_shared` come from allocating the object and the reference count in a single place, so calling `make_shared` can lead to a different size allocation. Someone could have a custom `operator new`, and if it were not called (with the correct `size` operand), the observable behavior of the code would change. – Mankarse Jul 28 '14 at 09:01
  • So you want the standard to create a special case in the core language for one type only (which would probably take quite a bit of work to specify correctly), all to save you from typing a few characters? – T.C. Jul 28 '14 at 09:04
  • @Mankarse Also, I could write a specialization of `std::make_shared` for one of my own types, which did something entirely different. (That would _not_ be good coding practice, but it is legal C++.) – James Kanze Jul 28 '14 at 09:05
  • @Mankarse: I'm a bit fuzzy about custom `operator new` implementations (as I've never used or encountered them in the wild yet), but wouldn't `make_shared` use a *placement new* for the object? And shouldn't code that implements a custom `operator new` handle such a *placement new* correctly as well, or be considered buggy if it doesn't? – DevSolar Jul 28 '14 at 09:08
  • @T.C. this isn't about laziness. I am trying to understand why this was intended as it is. – user3811839 Jul 28 '14 at 09:11
  • @Mankarse Couldn't the compiler look-up whether T has an overloaded new operator for custom memory management to decide? – user3811839 Jul 28 '14 at 09:12
  • @DevSolar: The `operator new` could be specific to the `X` class, and so would never get called for `make_shared`'s custome `X + refcount` class. If it were a global `operator new`, then just getting called with a different size operand would be an observable difference. @user3811839: Yes, anything is possible under the 'as if' rule... but compiler developers don't have infinite resources, and every optimization will likely increase compile times and increase the possibility for bugs, so may not be worth implementing. – Mankarse Jul 28 '14 at 09:14
  • 2
    `make_shared` can have a disadvantage - the object's memory won't be freed as long as there are weak pointers to it, even if there are no longer any shared pointers. So automatically using it, when the programmer hasn't specified it, could have a negative impact on memory usage, even if the "as if" rule does apply. – Mike Seymour Jul 28 '14 at 10:33

1 Answers1

1

It probably could be done, but adding another special rule just to save typing is not effective and not the philosophy of c++, what if someone were to come up with a better shared_ptr, if std::shared_ptr is a template then just make a better_shared template and you done. If it gets into the core language though its there for good.

Also note that it wouldn't save much typing:

auto x = make_shared<X>() vs shared_ptr<X> x(new X())

It would also be more complicated than "if I see new() and a shared pointer then use make_shared" because make_shared only replaces one of the 13 (I think) overloads of a shared_ptr constructor. The rules would undoubtedly be pages long in the standard which is big enough already. Just use make_shared and then you don't need the extra rule.

odinthenerd
  • 5,422
  • 1
  • 32
  • 61
  • Again, I am not against this concept- I just wanted to understand why compilers couldn't detect this automatically. Thanks. – user3811839 Jul 28 '14 at 09:46