/*
 * Copyright ©2026 Soham Pardeshi. All rights reserved.
 * Permission is hereby granted to students registered for University of
 * Washington CSE 333 for use solely during Summer Quarter 2026 for
 * purposes of the course. No other use, copying, distribution, or
 * modification is permitted without prior written consent. Copyrights
 * for third-party components of this work must be honored. Instructors
 * interested in reusing these course materials should contact the author.
 */

#include <cstdlib>
#include <iostream>
#include <memory>

using std::shared_ptr;
using std::weak_ptr;

// weak_ptr observes an object without owning it: it does not bump the
// strong reference count, so the back-edge no longer keeps the cycle
// alive. Compare valgrind output with sharedcycle.cc -- this one is clean.
//
// A weak_ptr cannot be dereferenced directly; lock() promotes it to a
// shared_ptr (or nullptr if the object is already gone), which is exactly
// the check you would have to write by hand with a raw back-pointer.
struct A {
  shared_ptr<A> next;
  weak_ptr<A> prev;
};

int main(int argc, char** argv) {
  shared_ptr<A> head(new A());
  head->next = shared_ptr<A>(new A());
  head->next->prev = head;  // weak: head's strong count stays 1

  if (shared_ptr<A> back = head->next->prev.lock()) {
    std::cout << "back edge still valid: " << (back == head) << std::endl;
  }

  return EXIT_SUCCESS;
}