Does a temporary shared_ptr returned by value have the counter incremented?

110 views Asked by At

I'm trying to understand how RVO works in conjunction with shared_ptr in this particular case.

Let's say I have this example code:

class A {
public:
  void action() {}
};

class Container {
public:
  shared_ptr<A> getA() { return m_a; }

private:
  shared_ptr<A> m_a;
};

Container cont{};
cont.getA()->action();

If I'm not wrong, in this situation the shared_ptr returned by getA() shouldn’t be copied/copy constructed because it's optimized by the compiler. So, in the last line, the shared_ptr I'm calling the action() function on should be directly the one contained in m_a inside the Container object?

In this case, if the pointer is not copied, is the internal reference count not incremented/decremented?

And because I'm using it as an r-value, it's optimized and I can directly use it to access the pointed object without any cost, like a raw pointer?

In case it's not like that, is there a way to avoid the cost of the increment/decrement? I'm not actually keeping the shared_ptr, but I'm using it only for an operation on the contained object.

Or, there could be any problem with the lifetime of the contained object?

2

There are 2 answers

2
Ted Lyngmo On BEST ANSWER

the shared_ptr returned by getA() shouldn’t be copied/copy constructed because it’s optimized by the compiler.

Yes, it will be copied. m_a is not a local variable so NRVO (named return value optimization) can't be done and returning it by value will indeed copy construct the returned shared_ptr<A>.

Demo

2
463035818_is_not_an_ai On

In a nutshell...

#include <iostream>

struct foo {
    foo() = default;
    foo(const foo&) { std::cout << "copy\n";}
};

foo bar() {
    foo f;
    return f;
}

int main() {
    foo g;
    g = bar();
}

Without eliding the copy: You call the function, inside the function there is f, the function returns, f gets copied into the returned value, f gets destroyed, you now have g, a copy of f.

The idea of eliding the copy is: A short moment where the copy is made aside, there never more than 1 object. The only effect of not making the copy is not making the copy, ie the side effects may be skipped and the above code does not print anything.

In your case this does not apply. m_a is a member. It is not a function local variable. A copy must be made, because the object returned from the function is distinct from the member.

Live Demo

Live Demo with copy elision disabled

Yes the temporary returned from the function is a copy. The ref count of the shared pointer is decremented at the end of the full expression.