views:

226

answers:

2

Profiling some code that heavily uses shared_ptrs, I discovered that reset() was surprisingly expensive.

For example:

struct Test {
    int i;
    Test() {
        this->i = 0;
    }
    Test(int i) {
        this->i = i;
    }
} ;
...
auto t = make_shared<Test>(1);
...
t.reset(somePointerToATestObject);

Tracing the reset() in the last line (under VC++ 2010), I discovered that it creates a new reference-counting object.

Is there a cheaper way, that reuses the existing ref-count and does not bother the heap?

+3  A: 

In the general case, you can't reuse the existing ref count because there may be other shared_ptrs or weak_ptrs using it.

If you can create somePointerToATestObject using make_shared(), then the implementation may use a single heap allocation for both the ref counts and the object. That will save you one of the heap allocations.

James McNellis
Unfortunately, reset() does not have a version that gets a shared_ptr<> as a parameters
Paul Oyster
@Paul: Right; you simply assign it as in `t = otherSharedPtr`.
James McNellis
I don't understand this answer. `tr1::shared_ptr` (unlike `boost::shared_ptr`) has no `reset` overload that takes another `shared_ptr`. Every invocation of `reset` has to create a reference count to bind to the supplied pointer because there is no way (`enable_shared_from_this` is not a requirement) to get at any existing reference count even if the supplied pointer is currently owned by another `shared_ptr`. If the supplied pointer is owned by another smart pointer (`shared_ptr` or otherwise) surely it's a programmer error to use `reset` and "tell" `shared_ptr` that it has ownership?
Charles Bailey
@Charles: Right. Like I said in the comment, one should simply use assignment. What I was trying to say in the answer was that when `somePointerToATestObject` is created, it should be immediately assigned to a `shared_ptr`. Then you don't have to worry about using `reset()` at all with it. I'm not sure I understand which part you disagree with :-/.
James McNellis
It's your first sentence that confuses me. If `somePointerToATestObject` being passed to `reset` then it can't be anything but a raw pointer so I don't understand where the "existing ref count" even comes from. Raw pointers aren't (necessarily) associated with an existing reference count. If the raw pointer actually comes from another `shared_ptr` then it's an out and out programmer error. There's no way that `reset` can or should use its reference count; it would be a violation of the interface.
Charles Bailey
@Charles: Ohhhhh. I meant the ref count from the object that the `shared_ptr` was pointing to before the reset, which is what I thought the OP was talking about when he referred to "reusing the existing ref count." That can't be done for the general case, both because `shared_ptr` doesn't have sole owner semantics (and if it did then it wouldn't need reference counting).
James McNellis
Duh! Makes total sense now. I think I'd subconsiously discounted the meaning that we were talking about the reference count associated with the object (if any) being released because it's obvious that that reference count must stay with the released object as it may not be being deleted. The whole talk about existing reference count had me wondering what type `somePointerToATestObject` could be if it was both useable with `reset` and had an existing reference count.
Charles Bailey
A: 

Forget about it. shared_ptr reset is not your bottleneck and will never be.

John
Never is a very strong word with regards to software development. If you're having a shared_ptr being copy constructed in an inner loop, then it is going to be your bottleneck. If it's used correctly it should not be a bottleneck, true, but that does not mean it is never a bottleneck.
Billy ONeal
You haven't really answered the question, John. If you don't like the question, vote it down and post a comment why. But I think it's a good question. Even if that particular method won't ever be a bottleneck, it can still be useful to understand what it is about that method that makes it the way it is, so we can learn from it and apply our new knowledge to other problems we encounter.
Rob Kennedy