Destructor with unique pointer and threads

Hi there!

Take this example code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <string.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <memory>

class A
{
public:

    void print()
    {
        printf("Just a dummy method\n");
    }

    ~A()
    {
        printf("A destructor\n");
    }
};

static std::queue<std::unique_ptr<A>> myqueue;
static std::condition_variable condition;
static std::mutex mutex;

static std::unique_ptr<A> dequeue()
{
    std::unique_lock<std::mutex> lock(mutex);

    condition.wait(lock, []
    {
        return !myqueue.empty();
    });

    std::unique_ptr<A> ret = std::move(myqueue.front());
    myqueue.pop();
    return ret;
}

static void enqueue(std::unique_ptr<A> element)
{
    std::lock_guard<std::mutex> lock(mutex);
    myqueue.push(std::move(element));
    condition.notify_one();
}

static void run()
{
    while (true)
    {
        std::unique_ptr<A> element = dequeue();
        element->print();
    }
}

int main()
{
    std::thread mythread(run);
    char input[10];

    do
    {
        scanf("%s", input);
        enqueue(std::unique_ptr<A>(new A));
    }
    while (strcmp(input, "quit") != 0);

    mythread.join();
    return 0;
}




If you run this example and set a breakpoint in the destructor of 'A' (main.cpp:20) to see when the object is deleted, you will see that 'A' objects are deleted in line 53, that is :

 
std::unique_ptr<A> element = dequeue();


How is this possible?? The next instruction is 'element->print()', which is still using an object that is already deleted.

Thanks a lot!
Line 45:
 
myqueue.push(std::move(element));


should be:
 
myqueue.emplace(std::move(element));

It's nothing to worry about. For some reason GCC assigns the destructor to the line where the object is created.

Both push or emplace should work fine in this case.
Last edited on
Yes, using 'emplace' causes the same behavior.

It is not that I was worried (as line 54 is not throwing a segmentation fault), I was just curious about that weird behavior.

Thanks a lot!!
Well, the behaviour of the program is correct, it's just that the debug information that GCC generates is misleading. It has nothing to do with unique_ptr or anything in your program. It always does it this way.

Below is a simplified version of your program that exhibits the exact same phenomenon. The strings are outputted in the correct order but if you place a breakpoint in the destructor the stack trace will show the destructor as being called on line 20.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

class A
{
public:

    void print()
    {
        printf("Just a dummy method\n");
    }

    ~A()
    {
        printf("A destructor\n");
    }
};

int main()
{
    A element;
    element.print();
    
}
Just a dummy method
A destructor


If you use Compiler Explorer to look at the code (https://godbolt.org/z/3fi_sw) you can clearly see which instructions are being mapped to which lines by comparing the background colours (A element; and call A::~A() are both coloured yellow). If you switch compiler to Clang (https://godbolt.org/z/-_TYas) you'll see that the destructor is instead mapped to the closing } where the object goes out of scope, which is probably more intuitive.
Last edited on
Topic archived. No new replies allowed.