Why is the shared_ptr NULL after a throw

Viewed 70

I have a shared_ptr in C++ that I want to throw as an exception. I was writing a test case that used an equivalent situation to this in gcc 6.4.0 and got stuck.

I don't understand why x is NULL after the exception has been handled, even though it hasn't gone out of scope or been assigned to.

#include "stdafx.h"
#include <iostream>
#include <memory>
#include <string>
using namespace std;

class S {
private:
    string s;
public:
    string String()
    {
        return s;
    }
    S(string a) : s(a)
    {
        cout << "S::S( " << a << " )" << endl;
    }
    ~S()
    {
        cout << "S::~S( " << String() << " )" << endl;
    }
};
int main(int argc, char* argv[])
{
    shared_ptr< S > x = make_shared<S>("hello world");
    cout << "Before throw" << endl;
    try {
        throw x;
    }
    catch (shared_ptr<S> e) {
        cout << "Caught it!" << endl;
        if (e) {
            cout << e->String() << endl;
        }
    }
    cout << "After throw" << endl;

    if (!x) {
        cout << "X is Null" << endl;
    }
    cout << "I'm done" << endl;
    return 0;
}

Visual Studio 2013 does what I expect:

S::S( hello world )
Before throw
Caught it!
hello world
After throw
I'm done
S::~S( hello world )

but GCC 6.4.0 (from Cygwin) does not:

S::S( hello world )
Before throw
Caught it!
hello world
S::~S( hello world )
After throw
X is Null
I'm done

Is there something going on here that I don't understand that makes GCC's behavior legal? Can I make it work in gcc as I intended?

[This is the same gcc bug as referred to in the question mentioned in the comments. I was hoping for a way to continue test case development for my project. The solution I found was to put the "try/catch" inside of separate function that took x as a parameter.]

[The bug is more subtle than it seems. If you add "swap(x, e);" inside the exception handler, after the handler returns, x is not longer empty but e is null within the handler. I was trying to save the S instance and to understand the situation better. When I added that swap, not only was x not empty at the end (which I expected), e was null after the swap which was completely unexpected. Adding the swap changed the output to

S::S( hello world )
Caught it!
S::~S( hello world )

It's not obvious why swapping two things that should be the same does that.]

0 Answers
Related