#include <iostream>
#include <memory>

using namespace std;

class Foo {
public:
  Foo() : _x(_xc++) {
    cout << "Default ctor(" << id() << ")" << endl;
  }

  Foo(const string& s) : _s(s), _x(_xc++) {
    cout << "Ctor(" << id() << ")" << endl;
  }

  Foo(const Foo& rhs) : _s(rhs._s), _x(_xc++) {
    cout << "Copy ctor(" << rhs.id() << ") -> " << id() << endl;
  }

  Foo(Foo&& rhs) : _s(rhs._s), _x(rhs._x) {
    cout << "Move ctor(" << rhs.id() << ") ->" << id() << endl;
  }

  Foo& operator= (const Foo& rhs) {
    _s = rhs._s;
    _x = _xc++;
    cout << "Copy(" << id() << ")" << " = " << rhs.id() << endl;
    return *this;
  }

  Foo& operator= (Foo&& rhs) {
    _s = rhs._s;
    _x = rhs._x;
    cout << "Move(" << id() << ")" << " = " << rhs.id() << endl;
    return *this;
  }

  void bar() {
    cout << "Foo::bar() : " << id() << endl;
  }

  ~Foo() {
    cout << "Dtor(" << id() << ")" << endl;
  }
private:
  string id() const {
    return _s + "/" + to_string(_x);
  }

  string _s;
  int _x;
  static int _xc;
};

int Foo::_xc = 0;

void baz(shared_ptr<Foo> foo) {
  foo->bar();
}

unique_ptr<Foo> createFoo() {
  return unique_ptr<Foo>(new Foo("unique"));
}

int main(int argc, char** argv) {
  shared_ptr<Foo> p(new Foo("shared"));

  p->bar();
  baz(p);
  auto foo = createFoo();
  foo->bar();

  return 0;
}