Skip to content

Latest commit

 

History

History
133 lines (119 loc) · 3.89 KB

File metadata and controls

133 lines (119 loc) · 3.89 KB

How to use std::shared_ptr

Here we create two instances of a std::shared_ptr and then make them point to each other. This creates a deadlock which can only be resolved by calling reset() upon which the pointers can then be destructed.

To create a shared pointer you can either use the following which is a bit long winded

    std::shared_ptr<class Foo> sptr(new Foo("foo2"));

Or, the following which hides the use of "new" but also invokes the copy constructor. If you don't want that, use the above.

    auto sptr = std::make_shared< class Foo >(Foo("foo1"));

Example:

#include <iostream>
#include <memory>
#include <sstream>

typedef std::shared_ptr< class Foo > Foop;

class Foo
{
private:
  std::string data;  // local data for foo for debugging
  Foop        other; // pointer to other Foo's so we can make a deadlock
public:
  Foo(std::string data) : data(data) { std::cout << "new " << to_string() << std::endl; }
  Foo(const Foo &o)
  {
    std::cout << "copy constructor " << to_string() << std::endl;
    data  = o.data;
    other = o.other;
  }
  ~Foo()
  {
    // Note, other.reset will be called for us
    std::cout << "delete " << to_string() << std::endl;
  }
  void addref(Foop o)
  {
    other = o;
    std::cout << "other use_count now " << other.use_count() << std::endl;
  }
  void delref(void)
  {
    other.reset();
    std::cout << "other use_count now " << other.use_count() << std::endl;
  }
  std::string to_string(void)
  {
    auto              address = static_cast< const void              *>(this);
    std::stringstream ss;
    ss << address;
    return "Foo(" + ss.str() + ", data=" + data + ")";
  }
};

int main(void)
{
  // Create a copy constructed class and share it between two pointers:
  auto sptr1 = std::make_shared< class Foo >(Foo("foo1"));
  std::cout << "sptr1 ref count now " << sptr1.use_count() << std::endl;
  auto sptr2 = sptr1;
  std::cout << "sptr2 ref count now " << sptr2.use_count() << std::endl;

  // Try to create a deadlock:
  sptr1->addref(sptr2);
  std::cout << "sptr1 ref count now " << sptr1.use_count() << std::endl;
  sptr2->addref(sptr1);
  std::cout << "sptr2 ref count now " << sptr2.use_count() << std::endl;

  // Undo the 'deadlock':
  sptr1->delref();
  std::cout << "sptr1 ref count now " << sptr1.use_count() << std::endl;
  sptr2->delref();
  std::cout << "sptr2 ref count now " << sptr2.use_count() << std::endl;

  // Release the shared sptrs, expect foo1 to be destroyed:
  sptr1.reset();
  std::cout << "sptr1 ref count now " << sptr1.use_count() << std::endl;
  sptr2.reset();
  std::cout << "sptr2 ref count now " << sptr2.use_count() << std::endl;

  // You can also create shared pointers WITHOUT copy constructor overhead
  std::shared_ptr< class Foo > sptr0(new Foo("foo0"));
  std::cout << "sptr0 = " << (sptr0.get() ? sptr0->to_string() : "nullptr") << std::endl;
}

To build:

cd std_shared_ptr
rm -f *.o example
clang -std=c++2a -Werror -g -O3 -fstack-protector-all -ggdb3 -Wall -c -o main.o main.cpp
clang  main.o -lstdc++  -o example
./example

Expected output:

�[31;1;4mCreate a copy constructed class and share it between two pointers:�[0m
new Foo(0x7ffc1cc11df0, data=foo1)
copy constructor Foo(0x56425a0aef00, data=)
delete Foo(0x7ffc1cc11df0, data=foo1)
sptr1 ref count now 1
sptr2 ref count now 2

�[31;1;4mTry to create a deadlock:�[0m
other use_count now 4
sptr1 ref count now 3
other use_count now 4
sptr2 ref count now 3

�[31;1;4mUndo the 'deadlock':�[0m
other use_count now 0
sptr1 ref count now 2
other use_count now 0
sptr2 ref count now 2

�[31;1;4mRelease the shared sptrs, expect foo1 to be destroyed:�[0m
sptr1 ref count now 0
delete Foo(0x56425a0aef00, data=foo1)
sptr2 ref count now 0

�[31;1;4mYou can also create shared pointers WITHOUT copy constructor overhead�[0m
new Foo(0x56425a0aef40, data=foo0)
sptr0 = Foo(0x56425a0aef40, data=foo0)
delete Foo(0x56425a0aef40, data=foo0)