2

In the code below, I want the use_count() of the shared_ptr moved into the std::async to be 1:

#include <memory>
#include <iostream> 
#include <future> 

using namespace std;

void fun(shared_ptr<int> sp)
{
    cout << "fun: sp.use_count() == " << sp.use_count() <<
        " (in gcc 4.6.3, is there a way to make this 1?)\n";
}

int main()
{
    auto sp1 = make_shared<int>(5);

    auto fut = async(
        launch::async,
        fun,
        move(sp1)
    );
}

My platform uses gcc 4.6.3, and the code above gives this output (fun: sp.use_count() == 2):

fun: sp.use_count() == 2 (in gcc 4.6.3, is there a way to make this 1?)

On coliru.stacked-crooked.com, I get the behavior that I want (fun: sp.use_count() == 1):

fun: sp.use_count() == 1 (in gcc 4.6.3, is there a way to make this 1?)

I'm not sure what compiler coliru is using, but I'm guessing it's newer than gcc 4.6.3.

Is there some way, some workaround, to get the behavior I want, without having to upgrade my compiler from gcc 4.6.3?

Quokka
  • 174
  • 1
  • 3
  • 10
  • 5
    GCC 4.6 is very old by now, and its support for C++11 is quite lacking. If you can you should upgrade. – Some programmer dude Nov 01 '17 at 15:18
  • If I had to guess, I'd say the count being 2 happens because your compiler is not doing copy elision for the `sp` argument to `fun`. What if you don't construct `sp1` explicitly, but as a temporary in the async call? – AVH Nov 01 '17 at 15:23
  • taking a guess here, but what happens if you change the parameter value to be an rvalue reference (`&&`) instead? – default Nov 01 '17 at 15:26
  • @Darhuuk I just tried that, and the `use_count()` is still `== 2` in `fun()`. – Quokka Nov 01 '17 at 15:27
  • 1
    @Default I did try that, but it won't even compile on my platform (ARM gcc 4.6.3). It does work on coliru though ([link](http://coliru.stacked-crooked.com/a/0fd3dc23236c8a4c)). – Quokka Nov 01 '17 at 15:28
  • 1
    Copy elision, references and whatnot isn't relevant here, the old `shared_ptr` should no longer hold a reference after the move, regardless of how the moved to value is later dealt with – Passer By Nov 01 '17 at 15:45

2 Answers2

1

a possible workaround could be

void fun(shared_ptr<int>* sp)
{
    unique_ptr<shared_ptr<int>> guard(sp);

    cout << "fun: sp.use_count() == " << sp->use_count() <<
        " (in gcc 4.6.3, is there a way to make this 1?)\n";
}

int main()
{
    auto sp1 = make_shared<int>(5);

    auto fut = async(
        launch::async,
        fun,
        new shared_ptr<int>(move(sp1))
    );
}

that said, it would be interesting to see where gcc463 makes the extra copy in the original code; it seems like the temporary given by decay_copy in async() is not forwarded to fun()'s parameter as an rvalue as it should be. Can't you step in with your debugger to see what's going on ?

Massimiliano Janes
  • 5,524
  • 1
  • 10
  • 22
0

Although std::async makes copies of all arguments, when invoking the function it perfect-forwards the arguments to the callable, so that the argument value category is preserved.

The arguments to std::async are only required to be MoveConstructible, otherwise it would not be possible to pass std::unique_ptr into std::async.

In other words, the correct behaviour is sp.use_count() == 1 and this is what I observe with an old g++-5.3.1.


Check whether the following code compiles with the compiler where you observe sp.use_count() == 2:

using namespace std;

void fun(unique_ptr<int> p) {
    cout << "fun " << *p << '\n';
}

int main() {
    unique_ptr<int> sp(new int{1});

    auto fut = async(
        launch::async,
        fun,
        move(sp)
    );

    fut.get();
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • That doesn't compile on my platform (ARM gcc 4.6.3). It can be seen online on Wandbox. Wandbox doesn't have gcc 4.6.3, but it has gcc 4.6.4, and it doesn't compile on that version either: ([link](https://wandbox.org/permlink/hpUJIRPSyrePHLqo)). However, it does compile on gcc 4.7.3: ([link](https://wandbox.org/permlink/EiTlxiGvrreWk4tj)) I'm trying to avoid upgrading my compiler, but if I want this behavior it's looking more and more like that's what I'm going to have to do... – Quokka Nov 01 '17 at 16:33