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

unique_ptr<int> unique_dangling()
{
  int x = 9;
  unique_ptr<int> px(&x);
  //return px;              // unique pointer to nowhere (this compiles)
  return make_unique<int>(8); // this will always heap-allocate
}

void print_unique(unique_ptr<int> px)
{
  cout << "unique pointer points to " << *px << endl;
}

void loser() // no good function just taking up stack space.
{
  int x;
}

int main()
{
  int *x = new int();
  *x = 1;
  unique_ptr<int> u1(x);
  unique_ptr<int> u2(x); // this compiles. NOW THAT'S REALLY UNIQUE!

  unique_ptr<int> u3 = make_unique<int>(4); // always use make_unqiue
  // to create unique pointers.
  cout << *u3 << endl;

  *u1 += 1;
  cout << *u2 << endl;   // unique my ass - prints 2
  print_unique(move(u2)); // move required - ownership passes to print_unqiue

  cout << *unique_dangling() << endl; // prints 9, but for how long?
  unique_ptr<int> px = unique_dangling();
  print_unique(move(px));  // stack ruined by call to move, print_unique

  // program will crash on exit because it will try to deallocate the
  // same heap memory for x twice, once when the moved px is destroyed
  // exit from print_unqiue, and once when u1 is destroyed on exit from
  // main.
  return 0;
}//main

/*
The fundamental problem of unique_ptr is that in C++ they are built on
top of native pointers, and it is not possible to separate them
completely from native pointers.  The example with u1 and u2 shows the
contradiction that setup implies.  In order for this idea to really
work, unique_ptr needs to be a native data type, and not just
something that relies on the existence of raw pointers.  That is, we
must be able to create heap-allocated memory and a unique pointer to
it in one lock step, and never mix the unique_ptr with raw pointers.
The make_unique function (since C++ 2014), does this to an extent.  But
there is no enforcement that this is the only way that unique_ptr's are
created.

Thus, although being a good idea, unique_ptr is not enough to solve the
memory management problem in C++.  In order for it to really work, it
needs to be a native part of the language itself, and not just something
that's added on top of existing features.
*/

struct point {
  int x, y;
  point(int a, int b) {x=a; y=b;}
  void print() {cout << x << "," << y << endl;}
};
  

void testpoint()
{
  unique_ptr<point> p1 = make_unique<point>(4,2);
  unique_ptr<point> p2 = make_unique<point>(5,9);
  p1->print();
  p2->print();
}

