5 ms·
I disagree with this article. There is a case where you might want to pass a const reference to a shared pointer. Suppose you have a class class Foo {
by jeremysalwen 7y ago
I disagree with this article. There is a case where you might want to pass a const reference to a shared pointer.
Suppose you have a class
class Foo {
shared_ptr<Widget> widget;
bool has_widget();
void set_widget(shared_ptr<widget> widget);
}
and you are writing a function which may call set_widget(), it can save an unnecessary shared_ptr copy if you pass it as a const reference:
void maybe_set_widget( Foo& foo, const shared_ptr<Widget>& widget) {
if(!foo.has_widget()) {
foo.set_widget(widget);
}
}
Doing a quick google search finds that Herb Sutter agrees with me (https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/ https://herbsutter.com/2013/06/05/gotw-91-solution-smart-poi...):
>Use a const shared_ptr& as a parameter only if you’re not sure whether or not you’ll take a copy and share ownership
- afc 7y agoThank you for writing that. I was about to write ... exactly the same. There is a very legitimate use case for passing the const reference to the shared pointer that the article doesn't consider at all, which you've explained very well.
- w0utert 7y agoThis is not untrue, but the counterpoint would be that the intersection of a) the number of situations where the shared pointer copy would have any measurable influence on performance, and b) using shared pointers is a good idea for that particular problem in the first place, is likely vanishingly small. The main performance ‘problem’ with shared pointers is locking and contention in heavily multithreaded scenarios, which is why pretty much nobody uses a reference counting memory model for these kinds of things. In the vast majority of single or lightly threaded scenarios I think you will be hard pressed to find any reasonable algorithm implemented using shared pointers where the reference counting overhead is even measurable. So it’s not a strange thing at all to deprioritize hypothetical performance gains over clear intent of your code. Best thing is to stay away from shared pointers unless you really need them anyway, as they promote designs with sloppy ownership semantics. Been there, done that, try to get rid of them years later... :-/ The almost obligatory Herb Sutter reference made me chuckle by the way. He says so many things about what he thinks is the right thing to do in C++, and gets quoted almost as an absolute authority on good C++ practices, but quite often (not always, mind you) I find his arguments weak and unconvincing, and his recommendations sometimes downright counterproductive.
- linkdd 7y ago> Best thing is to stay away from shared pointers unless you really need them anyway, as they promote designs with sloppy ownership semantics. Could you elaborate? I'm not an expert in C++ but smart pointers did simplify a lot of my code and I never met the case where it was a problem. Like everything else in C++ (and any low-level language), they should be used carefully.
- mytherin 7y agoIn my experience unique pointers are usually a better fit than shared pointers. That is not to say shared pointers do not have their place, but they can definitely be abused. Especially for developers that come from garbage collected languages, it might be tempting to replace all pointers with shared pointers and call it a day. Not only can this cause performance issues when these are used in performance critical locations, but you can also lose track of who owns what very easily. It is also very easy to accidentally create cyclic references with shared pointers. Suppose you have a class like this: struct Node { shared_ptr<Node> parent; shared_ptr<Node> child; }; This rather innocent looking class creates a cycle when you fill in the values, because the parent and child reference each other. That cycle now means your nodes will not be cleaned up anymore. Unique pointers do not have any of these problems. They cannot create cycles, are very cheap and they make it very explicit who owns what. They are not suitable for every situation (i.e. when there is actually shared ownership shared pointers should be used) but in most situations I find that they are sufficient and have a lot less pitfalls than shared pointers.
- lbrandy 7y agoThis is the only good use of a const& shared_ptr which is when you 1) only _might_ want to claim shared ownership of the thing, and 2) the perf of those unnecessary refcounts matter. However, you missed a _super_ important caveat of this which is very subtle and very awful. And that is all of the code being executing here between the start of the function and the copy of the shared_ptr is doing it without the protection of the reference count on the shared pointer. It's entirely conceivable that, for example, the `has_widget` function, while executing, invalidates the original shared_ptr passed in and thus makes your eventual use of that shared_ptr invalid.
- PaulDavisThe1st 7y agoHow would it invalidate it?
- bluGill 7y agoYou would need to pass it across threads. At least that is all I can come up with.
- PaulDavisThe1st 7y agothat will not invalidate it. it might have other (negative) implications, but it does not invalidate it.
- bluGill 7y agoIt doesn't automatically invalidate it, but it makes possible things that would invalidate it.
- PaulDavisThe1st 7y agosuch as?
- 7y ago
- beached_whale 7y agoI think another way to put it is that when I am calling a non-async function, for instance, I am not sharing ownership of the shared object. So calling a normal function that blocks probably would be best as the Widget ref/Widget * with/without const depending on the type of operation. But the copy of a shared_ptr<T> is saying that we are sharing ownership and the cases where that applies. An async operation, like the argument to a thread or a task, probably would require sharing ownership/lifetime of the object. Or it may be a transfer of ownership via std::move.
- mmazing 7y agoI want a new term - "author smell" or "article smell". I loathe when someone or some article rants on about their silver bullet solution, or alternatively, that doing some thing is always bad. I learned a test taking strategy early in my life - when faced with a multiple choice question, if you see "always" or "never", that answer is usually incorrect. To come back around to this article and similar software development articles - we have many tools in our toolbox, the trick is knowing when to use (or not use) a particular tool. Never throw your tools away.
- saagarjha 7y agoThere’s a few exceptions to your rule, too ;) Never use std::auto_ptr, for example.