Search code examples
c++c++11shared-ptrsmart-pointers

shared_ptr not reporting referenced object deletion


I'm running this code in MS Visual Studio 10,

#include <iostream>
#include <memory>
using namespace std;

class A
{
    int i;
public:
    A(int j) : i(j) {}
    ~A() {}
    void fun()
    {
        cout << "A::i = " << i << endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    A aObj(12);
    std::shared_ptr<A> const pObj (&aObj,
                [] (A* pA) {
                    cout << "lambda deleter" << endl;
                });
    aObj.~A();
    pObj->fun();
    return 0;
}

This prints / holds data members for an object, that has already been deleted, without reporting any type of error.

Please write on:

  1. Why shared_ptr pObj doesn't report (at run-time) that underlying object has already been deleted?
  2. Since I'm creating a const shared_ptr, means can't use it to refer any other object, why lambda is not invoked at object deletion.
  3. Can weak_ptr be helpful in similar cases. weak_ptr is used with semantics that the lifetime of a reference to an object outlives the object it refers to.

Solution

  • Why shared_ptr pObj doesn't report (at run-time) that underlying object has already been deleted?

    Because shared_ptr is not magic1. It knows when the contained object has been deleted only when it deletes that object. When you use a shared_ptr, you have entered into a contract with shared_ptr. One of the tenants of that contract (indeed, of any contract you enter into with a smart pointer of any kind) is that you don't get to delete the pointer. The shared_ptr instance owns the pointer, and it will delete it, not you.

    Violating that contract leads to undefined behavior.

    Since I'm creating a const shared_ptr, means can't use it to refer any other object, why lambda is not invoked at object deletion.

    Again, the shared_ptr can only know that the contained object is deleted when it deletes it. It knows nothing about the state of the object if you break the contract.

    Can weak_ptr be helpful in similar cases. weak_ptr is used with semantics that the lifetime of a reference to an object outlives the object it refers to.

    weak_ptr is no more magically endowed than shared_ptr. weak_ptr only knows what the shared_ptr set it was created with knows about. If the shared_ptr doesn't know that the object's been deleted, the weak_ptr won't either.


    1 By "magic", I mean doing something that's just not possible in C++. If you want to know that a function has been called (and a destructor is a function call), there are only two ways to do that. Either that function tells you it's been called (by setting some value you can see), or you set up a system whereby people call your function which then calls the other function.

    The first system requires a function that is written explicitly to let people know that it's been called. You can't do that with any old function; it has to be designed for that. The second system requires that everyone use your new function and nobody uses the old one. If someone uses the old one directly, your code won't know about it.

    The first method is called "intrusive" (because it requires that you write your object in a special way), and smart pointers that use it are called "intrusive smart pointers". The second method is non-intrusive (doesn't require special code for the object). shared_ptr, and all currently standard smart pointers, are non-intrusive. This means you can use them with any object, but you can only use them if you abide by the contract.

    C++ does not offer a third way. Therefore, a class that could somehow intrude on a destructor call, a class that could know it has been called without that destructor explicitly telling it that it has been, is not possible. And therefore would be magic.