#include <iostream>
#include <memory>
#include <utility>
#include <vector>
class TraceObject {
public:
explicit TraceObject(const std::string& name) : name_(name) {
std::cout << "[TraceObject] " << name_ << " constructed" << std::endl;
}
~TraceObject() {
std::cout << "[TraceObject] " << name_ << " destructed" << std::endl;
}
void greet() const {
std::cout << "Hello from " << name_ << std::endl;
}
private:
std::string name_;
};
class NodeB;
class NodeA {
public:
NodeA() { std::cout << "NodeA constructed" << std::endl; }
~NodeA() { std::cout << "NodeA destructed" << std::endl; }
void setPartner(const std::shared_ptr<NodeB>& b) { partner_ = b; }
private:
std::shared_ptr<NodeB> partner_;
};
class NodeB {
public:
NodeB() { std::cout << "NodeB constructed" << std::endl; }
~NodeB() { std::cout << "NodeB destructed" << std::endl; }
void setPartner(const std::shared_ptr<NodeA>& a) { partner_ = a; }
private:
std::shared_ptr<NodeA> partner_;
};
class FixedNodeB;
class FixedNodeA {
public:
FixedNodeA() { std::cout << "FixedNodeA constructed" << std::endl; }
~FixedNodeA() { std::cout << "FixedNodeA destructed" << std::endl; }
void setPartner(const std::shared_ptr<FixedNodeB>& b) { partner_ = b; }
void usePartner() const;
void greet() const {
std::cout << "FixedNodeA::greet() called" << std::endl;
}
private:
std::shared_ptr<FixedNodeB> partner_;
};
class FixedNodeB {
public:
FixedNodeB() { std::cout << "FixedNodeB constructed" << std::endl; }
~FixedNodeB() { std::cout << "FixedNodeB destructed" << std::endl; }
void setPartner(const std::shared_ptr<FixedNodeA>& a) { partner_ = a; }
void usePartner() const;
private:
std::weak_ptr<FixedNodeA> partner_;
};
void FixedNodeA::usePartner() const {
if (partner_) {
std::cout << "FixedNodeA accessing partner" << std::endl;
partner_->usePartner();
} else {
std::cout << "FixedNodeA has no partner" << std::endl;
}
}
void FixedNodeB::usePartner() const {
if (auto sp = partner_.lock()) {
std::cout << "FixedNodeB successfully locked weak_ptr, partner exists" << std::endl;
sp->greet();
} else {
std::cout << "FixedNodeB's weak_ptr has expired, partner already released" << std::endl;
}
}
struct CustomDeleter {
void operator()(TraceObject* p) const {
std::cout << "Custom deleter releases TraceObject" << std::endl;
delete p;
}
};
int main() {
std::cout << "========== C++ Smart Pointer Demonstration ==========" << std::endl;
std::cout << "\n--- 1. unique_ptr demonstration ---" << std::endl;
{
auto ptr1 = std::make_unique<TraceObject>("unique_1");
ptr1->greet();
std::unique_ptr<TraceObject> ptr2 = std::move(ptr1);
if (!ptr1) std::cout << "ptr1 is now null" << std::endl;
ptr2->greet();
ptr2.reset(new TraceObject("unique_2"));
ptr2->greet();
TraceObject* raw = ptr2.release();
delete raw;
auto customDeleterLambda = [](TraceObject* p) {
std::cout << "Lambda deleter releases TraceObject" << std::endl;
delete p;
};
std::unique_ptr<TraceObject, decltype(customDeleterLambda)> ptr3(
new TraceObject("custom_deleter"), customDeleterLambda);
ptr3->greet();
}
std::cout << "unique_ptr demonstration complete" << std::endl;
std::cout << "\n--- 2. shared_ptr demonstration ---" << std::endl;
{
auto sp1 = std::make_shared<TraceObject>("shared_1");
std::cout << "Reference count: " << sp1.use_count() << std::endl;
{
auto sp2 = sp1;
std::cout << "After copy, reference count: " << sp1.use_count() << std::endl;
sp2->greet();
}
std::cout << "After sp2 destroyed, reference count: " << sp1.use_count() << std::endl;
sp1.reset();
std::cout << "After reset, reference count: " << (sp1 ? sp1.use_count() : 0) << std::endl;
}
std::cout << "\n--- 3. weak_ptr basic demonstration ---" << std::endl;
{
auto sp = std::make_shared<TraceObject>("weak_demo");
std::weak_ptr<TraceObject> wp = sp;
std::cout << "weak_ptr not expired, lock result: " << (wp.lock() ? "valid" : "invalid") << std::endl;
sp.reset();
std::cout << "After shared_ptr released, weak_ptr expired: " << wp.expired() << std::endl;
std::cout << "lock result: " << (wp.lock() ? "valid" : "invalid") << std::endl;
}
std::cout << "\n--- 4. Circular reference demonstration (using shared_ptr mutual references, causing memory leak) ---" << std::endl;
{
std::shared_ptr<NodeA> a = std::make_shared<NodeA>();
std::shared_ptr<NodeB> b = std::make_shared<NodeB>();
a->setPartner(b);
b->setPartner(a);
std::cout << "Note: The above NodeA and NodeB will not be destructed, causing memory leak" << std::endl;
}
std::cout << "Circular reference block ended, but NodeA and NodeB not destructed, no destructor output visible." << std::endl;
std::cout << "\n--- 5. Breaking circular reference using weak_ptr (correct approach) ---" << std::endl;
{
auto a = std::make_shared<FixedNodeA>();
auto b = std::make_shared<FixedNodeB>();
a->setPartner(b);
b->setPartner(a);
a->usePartner();
std::cout << "Scope ending, FixedNodeA and FixedNodeB should be properly destructed." << std::endl;
}
std::cout << "Circular reference fix block ended, destructors called correctly." << std::endl;
std::cout << "\n--- 6. Storing smart pointers in containers ---" << std::endl;
{
std::vector<std::shared_ptr<TraceObject>> vec;
vec.push_back(std::make_shared<TraceObject>("vec_elem_1"));
vec.push_back(std::make_shared<TraceObject>("vec_elem_2"));
vec.push_back(std::make_shared<TraceObject>("vec_elem_3"));
std::cout << "Iterating container: " << std::endl;
for (const auto& elem : vec) {
elem->greet();
}
vec.clear();
std::cout << "Container cleared, all elements released" << std::endl;
}
std::cout << "\n--- 7. Converting unique_ptr to shared_ptr ---" << std::endl;
{
auto up = std::make_unique<TraceObject>("to_be_shared");
std::shared_ptr<TraceObject> sp = std::move(up);
std::cout << "unique_ptr ownership transferred to shared_ptr, reference count: " << sp.use_count() << std::endl;
sp->greet();
}
std::cout << "\n========== Program ended, all resources properly released ==========" << std::endl;
return 0;
}