🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Fixing confusing C++ shared pointer errors

Started by
20 comments, last by Gnollrunner 1 year, 10 months ago

@gnollrunner shared_ptr is great for a certain type of problems, and is designed to work in conjunction with the other standard library smart pointers. It is a suitable solution for many projects. If the built-in smart pointers don't fit your needs, don't use them.

Advertisement

Gnollrunner said:
On a side note IMHO std::shard_ptr is garbage, mainly because it uses twice as much memory as a normal pointer. In addition they lock you into other things like thread safety and a weak pointer counter whether you need those or not.

You're trying to trick the wrong programmer.

10x Faster Performance for VR: www.ultraengine.com

@Josh Klint I'm not trying to do anything but give my opinion. You can do a sizeof() yourself if you think I'm wrong. In any case if that stuff doesn't concern you go ahead and use them, but it would be a disaster for my project.

I don't think anybody is disputing that they are larger than the size of a raw pointer. I think we're disputing your claim that the are “garbage”.

If they don't work for you, don't use them. They work for many other people for a wide range of purposes. When you need to implement shared ownership it's a pre-built solution which works well in the general case. If you don't need shared ownership, or if there are some reason where you do need it but don't want the other aspects, you're free to use something else.

I think the original issue around the error messages has been resolved.

@frob Certainly something being “garbage” is a matter of opinion, so I don't think there is any point in arguing that. However for something that's been added to the standard library, it seems pretty bad to me. You don't need 2 raw pointers to implement a smart pointer. It was done for years with a single pointer. But if someone is happy using it, I'm not going to try to convince them not to. I was simply pointing out what I consider to be some major issues with it.

Gnollrunner said:

@Josh Klint I'm not trying to do anything but give my opinion. You can do a sizeof() yourself if you think I'm wrong. In any case if that stuff doesn't concern you go ahead and use them, but it would be a disaster for my project.

How would you design a smart shared pointer then you have to store a ref counter at the minmum somewhere. From what I can see in how std::shard_ptr is implemented its the same as most custom implementations I have seen in custom engines, except for the weak counter.
I would think you very much would like MT safeness on shared_ptrs because you really don't know where they are passed in a lot of the cases. I have had to deal with problems where the ref count was not thread safe and those are not fun bugs to look at, it cost us 6 months to fix that issue and in the end we ended up just making the refcount thread safe.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

@NightCreature83 If you use make_shared which you are encouraged to do the vast majority of the time, the control block is allocated with the object anyway, so there is no need for the second pointer. So it's almost always unnecessary. With any pointer heavy code it's a huge waste of space. Reference counting pointers were implemented as as a single pointers for a long time before std::make_shared. There are a few corner cases where you might want to use a separate control block, but burdening the main ref-counting pointer class with it seems silly to me. As for thread safety, I think that should be optional.

Again, if you want to use std::shared_ptr, go nuts. I'm not trying to tell anyone what and what not to use.

Gnollrunner said:
@NightCreature83 If you use make_shared which you are encouraged to do the vast majority of the time, the control block is allocated with the object anyway, so there is no need for the second pointer. So it's almost always unnecessary. With any pointer heavy code it's a huge waste of space. Reference counting pointers were implemented as as a single pointers for a long time before std::make_shared. There are a few corner cases where you might want to use a separate control block, but burdening the main ref-counting pointer class with it seems silly to me. As for thread safety, I think that should be optional.

Yes, the vast majority of the time. But not all the time. As I told you the last time, the STD must work in a vast majority of different cases. You can have a project that heavily uses c-libraries, and wants to wrap those classes generated by c-style “create” functions in a shared_ptr. Or some legacy-library that uses a factory-pattern that first returns a raw-pointer allocated with new, that needs to be wrapped in a shared-ptr in some cases. Note that personally I despise all those cases and never use anything other then make_unique/shared, pretty much, but I'm also not maintaining a standard-library that has to be used by people all over the globe.
So there is no one-pointer solution unless you can enforce the constraint of “shared_ptr must always be constructed with make_shared”. Would you honestly suggest that be something that could/should be implemented as a c++25 feature, for example?

Gnollrunner said:
Again, if you want to use std::shared_ptr, go nuts. I'm not trying to tell anyone what and what not to use.

Calling something “garbage” is a very strong sign of telling people not to use it. I'm calling Unity garbage, and I would certainly tell people not to use it.
shared_ptr works in 95% of the cases. The additional size will not make a real difference in most cases. Thats not garbage. If you really have a case where saving an additional pointer on your shared_ptr is making such a tremendous difference in performance or memory that you literally couldn't use shared_ptr, then you are certainly not the norm.

Juliean said:

Yes, the vast majority of the time. But not all the time. As I told you the last time, the STD must work in a vast majority of different cases. You can have a project that heavily uses c-libraries, and wants to wrap those classes generated by c-style “create” functions in a shared_ptr. Or some legacy-library that uses a factory-pattern that first returns a raw-pointer allocated with new, that needs to be wrapped in a shared-ptr in some cases. Note that personally I despise all those cases and never use anything other then make_unique/shared, pretty much, but I'm also not maintaining a standard-library that has to be used by people all over the globe.
So there is no one-pointer solution unless you can enforce the constraint of “shared_ptr must always be constructed with make_shared”. Would you honestly suggest that be something that could/should be implemented as a c++25 feature, for example?

There has been a one pointer solution since operator overloading was included in C++. Also there is no reason ref-counting pointers should be designed for the corner case. They could have provided more than one smart pointer type or added more options. As it stands you can do a custom class with it's ref-counting pointer in a few minutes.

Calling something “garbage” is a very strong sign of telling people not to use it.

Not at all. I have no problem with anyone else using std::shared_ptr. That choice doesn't affect me in the least. I'm giving my opinion and if someone disagrees, that's fine. It's not a personal insult. I think it's garbage, if you disagree that's OK with me.

Also it may work 100% of the time but 90% of the time it might be sub-optimal for the task.

For pointer-heavy code, yeah, that would make a difference. However, in my programs my pointers probably account for less than 1% of all memory allocated. I see them as just letting the compiler handle manual reference counting automatically.

10x Faster Performance for VR: www.ultraengine.com

This topic is closed to new replies.

Advertisement