📚 RetainPtr 智能指针系统详解

// Copyright 2016 The PDFium Authors
// BSD开源协议声明

#ifndef CORE_FXCRT_RETAIN_PTR_H_
#define CORE_FXCRT_RETAIN_PTR_H_

#include <stdint.h>

#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>

//#include "core/fxcrt/check.h"
//#include "core/fxcrt/compiler_specific.h"
#include "check.h"
#include "compiler_specific.h"

namespace fxcrt {

    // 用于std::unique_ptr的自定义删除器,调用Release()而非delete
    template <class T>
    struct ReleaseDeleter {
        inline void operator()(T* ptr) const { ptr->Release(); }
    };

    // 类似于base库的scoped_refptr,实现引用计数的智能指针
    template <class T>
    class /*TRIVIAL_ABI*/ RetainPtr {
    public:
        // 默认构造函数
        RetainPtr() noexcept = default;

        // 允许隐式转换nullptr
        // NOLINTNEXTLINE(runtime/explicit)
        RetainPtr(std::nullptr_t ptr) {}

        // 显式构造函数,接受原生指针
        explicit RetainPtr(T* pObj) noexcept : m_pObj(pObj) {
            if (m_pObj)
                m_pObj->Retain();  // 增加引用计数
        }

        // 拷贝构造函数
        RetainPtr(const RetainPtr& that) noexcept : RetainPtr(that.Get()) {}

        // 移动构造函数,转移所有权后原指针置空
        RetainPtr(RetainPtr&& that) noexcept { Unleak(that.Leak()); }

        // 类型转换的拷贝构造函数
        template <class U,
            typename = typename std::enable_if<
            std::is_convertible<U*, T*>::value>::type>
        RetainPtr(const RetainPtr<U>& that) : RetainPtr(that.Get()) {}

        // 类型转换的移动构造函数
        template <class U,
            typename = typename std::enable_if<
            std::is_convertible<U*, T*>::value>::type>
        RetainPtr(RetainPtr<U>&& that) noexcept {
            Unleak(that.Leak());
        }

        // 赋值nullptr操作符
        RetainPtr& operator=(std::nullptr_t) noexcept {
            Reset();
            return *this;
        }

        // 拷贝赋值操作符
        RetainPtr& operator=(const RetainPtr& that) {
            if (*this != that)
                Reset(that.Get());
            return *this;
        }

        // 移动赋值操作符
        RetainPtr& operator=(RetainPtr&& that) noexcept {
            Unleak(that.Leak());
            return *this;
        }

        // 类型转换的拷贝赋值操作符
        template <class U,
            typename = typename std::enable_if<
            std::is_convertible<U*, T*>::value>::type>
        RetainPtr& operator=(const RetainPtr<U>& that) {
            if (*this != that)
                Reset(that.Get());
            return *this;
        }

        // 类型转换的移动赋值操作符
        template <class U,
            typename = typename std::enable_if<
            std::is_convertible<U*, T*>::value>::type>
        RetainPtr& operator=(RetainPtr<U>&& that) noexcept {
            Unleak(that.Leak());
            return *this;
        }

        // 析构函数
        ~RetainPtr() = default;

        // 类型转换方法
        template <class U>
        U* AsRaw() const {
            return static_cast<U*>(Get());
        }

        // 转换为另一种类型的RetainPtr
        template <class U>
        RetainPtr<U> As() const {
            return RetainPtr<U>(AsRaw<U>());
        }

        // 重置指针
        void Reset(T* obj = nullptr) {
            if (obj)
                obj->Retain();  // 新对象增加引用计数
            m_pObj.reset(obj); // 旧对象自动释放
        }

        // 隐式转换为原生指针
        operator T* () const noexcept { return Get(); }
        // 获取原生指针
        T* Get() const noexcept { return m_pObj.get(); }

        // 交换两个智能指针
        void Swap(RetainPtr& that) { m_pObj.swap(that.m_pObj); }

        // 泄漏指针所有权
        T* Leak() { return m_pObj.release(); }
        // 接收泄漏的指针
        void Unleak(T* ptr) { m_pObj.reset(ptr); }

        // 比较操作符
        bool operator==(const RetainPtr& that) const { return Get() == that.Get(); }
        bool operator!=(const RetainPtr& that) const { return !(*this == that); }

        template <typename U>
        bool operator==(const U& that) const {
            return Get() == that;
        }

        template <typename U>
        bool operator!=(const U& that) const {
            return !(*this == that);
        }

        // 小于比较操作符
        bool operator<(const RetainPtr& that) const {
            return std::less<T*>()(Get(), that.Get());
        }

        // bool转换操作符
        explicit operator bool() const { return !!m_pObj; }
        // 解引用操作符
        T& operator*() const { return *m_pObj; }
        // 成员访问操作符
        T* operator->() const { return m_pObj.get(); }

    private:
        // 使用unique_ptr管理指针,自定义删除器
        std::unique_ptr<T, ReleaseDeleter<T>> m_pObj;
    };

    // 可被RetainPtr管理的基类,实现引用计数
    class Retainable {
    public:
        Retainable() = default;

        // 检查是否只有一个引用
        bool HasOneRef() const { return m_nRefCount == 1; }

    protected:
        // 虚析构函数
        virtual ~Retainable() = default;

    private:
        // 禁止拷贝构造和赋值
        Retainable(const Retainable& that) = delete;
        Retainable& operator=(const Retainable& that) = delete;

        // 友元声明,允许RetainPtr访问私有成员
        template <typename U>
        friend struct ReleaseDeleter;

        template <typename U>
        friend class RetainPtr;

        // 增加引用计数
        void Retain() const {
            ++m_nRefCount;
            CHECK(m_nRefCount > 0);  // 防止溢出
        }
        // 减少引用计数,当计数为0时删除对象
        void Release() const {
            CHECK(m_nRefCount > 0);
            if (--m_nRefCount == 0)
                delete this;
        }

        // 引用计数器,使用无符号类型
        mutable uintptr_t m_nRefCount = 0;
        static_assert(std::is_unsigned<decltype(m_nRefCount)>::value,
            "m_nRefCount必须是无符号类型,以确保Retain()中的溢出检查正常工作");
    };

}  // namespace fxcrt

// 导出常用类型
using fxcrt::ReleaseDeleter;
using fxcrt::Retainable;
using fxcrt::RetainPtr;

namespace pdfium {

    // 类似std::make_unique的工厂函数,创建RetainPtr
    template <typename T, typename... Args>
    RetainPtr<T> MakeRetain(Args&&... args) {
        return RetainPtr<T>(new T(std::forward<Args>(args)...));
    }

    // 包装原生指针为RetainPtr
    template <typename T>
    RetainPtr<T> WrapRetain(T* that) {
        return RetainPtr<T>(that);
    }

}  // namespace pdfium

// 宏定义,允许通过MakeRetain构造私有构造函数的类
#define CONSTRUCT_VIA_MAKE_RETAIN         \
  template <typename T, typename... Args> \
  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args)

#endif  // CORE_FXCRT_RETAIN_PTR_H_

🏗️ 整体架构

RetainPtr 是一个基于引用计数的智能指针系统,主要由以下几个部分组成:

组件 作用 特点
RetainPtr<T> 智能指针主体 管理对象生命周期,自动处理引用计数
Retainable 可被管理的基类 提供引用计数基础设施
ReleaseDeleter<T> 自定义删除器 调用 Release() 而非 delete
MakeRetain() 工厂函数 创建对象并包装为 RetainPtr

📋 Retainable 基类详解

核心定义

class Retainable {
public:
    Retainable() = default;
    bool HasOneRef() const { return m_nRefCount == 1; }

protected:
    virtual ~Retainable() = default;

private:
    Retainable(const Retainable&) = delete;
    Retainable& operator=(const Retainable&) = delete;

    // 友元声明,允许智能指针访问私有方法
    template <typename U> friend struct ReleaseDeleter;
    template <typename U> friend class RetainPtr;

    void Retain() const {
        ++m_nRefCount;
        CHECK(m_nRefCount > 0);  // 溢出检查
    }
    
    void Release() const {
        CHECK(m_nRefCount > 0);
        if (--m_nRefCount == 0)
            delete this;
    }

    mutable uintptr_t m_nRefCount = 0;
};

🔍 关键特性

特性 说明 重要性
虚析构函数 确保正确析构派生类 ⭐⭐⭐⭐⭐
删除拷贝语义 防止意外的对象复制 ⭐⭐⭐⭐
mutable 引用计数 允许在 const 对象上修改计数 ⭐⭐⭐⭐
溢出检查 防止引用计数回绕 ⭐⭐⭐
无符号计数类型 确保正确的算术行为 ⭐⭐⭐

🎯 ReleaseDeleter 自定义删除器

实现代码

template <class T>
struct ReleaseDeleter {
    inline void operator()(T* ptr) const { ptr->Release(); }
};

🔧 工作原理

场景 行为 结果
std::unique_ptr 析构 调用 ptr->Release() 减少引用计数,可能删除对象
引用计数 > 1 Release() 减少计数 对象继续存在
引用计数 == 1 Release() 减少到 0 调用 delete this

🚀 RetainPtr 核心类详解

🏗️ 内部结构

template <class T>
class RetainPtr {
private:
    std::unique_ptr<T, ReleaseDeleter<T>> m_pObj;
    
public:
    // 各种构造函数和操作符...
};

📊 构造函数汇总

构造函数 语法示例 引用计数变化 说明
默认构造 RetainPtr<Doc> ptr; 创建空指针
原生指针构造 RetainPtr<Doc> ptr(new Doc); +1 显式构造,增加计数
拷贝构造 RetainPtr<Doc> ptr2(ptr1); +1 共享所有权
移动构造 RetainPtr<Doc> ptr2(std::move(ptr1)); 转移所有权
类型转换构造 RetainPtr<Base> base(derivedPtr); +1 向上转型

⚙️ 关键方法详解

1. Reset() - 重置指针所有权
void Reset(T* obj = nullptr) {
    if (obj)
        obj->Retain();      // 新对象增加计数
    m_pObj.reset(obj);     // 旧对象自动释放
}

使用场景:

auto doc = MakeRetain<Document>();
doc.Reset(new Document("New"));  // 释放旧对象,管理新对象
doc.Reset();                    // 释放当前对象,变为空指针
2. Leak() / Unleak() - 手动所有权管理
T* Leak() { return m_pObj.release(); }      // 释放所有权,不减少计数
void Unleak(T* ptr) { m_pObj.reset(ptr); }  // 接管所有权,不增加计数

典型用法:

auto doc = MakeRetain<Document>();
Document* raw = doc.Leak();    // doc 变为空,raw 需要手动管理
// ... 使用 raw ...
doc.Unleak(raw);              // 重新接管所有权
3. 类型转换方法
// 静态类型转换
template <class U>
U* AsRaw() const { return static_cast<U*>(Get()); }

// 安全类型转换
template <class U>
RetainPtr<U> As() const { return RetainPtr<U>(AsRaw<U>()); }

使用示例:

class Derived : public Base { /*...*/ };

RetainPtr<Base> base = MakeRetain<Derived>();
RetainPtr<Derived> derived = base.As<Derived>();  // 安全向下转型

🔄 赋值操作符行为

操作符 等效代码 引用计数变化
ptr = nullptr ptr.Reset() 减少原对象计数
ptr1 = ptr2 ptr1.Reset(ptr2.Get()) 原对象-1,新对象+1
ptr1 = std::move(ptr2) ptr1.Unleak(ptr2.Leak()) 无变化,所有权转移

🏭 MakeRetain 工厂函数

核心实现

template <typename T, typename... Args>
RetainPtr<T> MakeRetain(Args&&... args) {
    return RetainPtr<T>(new T(std::forward<Args>(args)...));
}

🎯 CONSTRUCT_VIA_MAKE_RETAIN 宏

#define CONSTRUCT_VIA_MAKE_RETAIN         \
  template <typename T, typename... Args> \
  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args)

使用方式:

class SecretDoc : public Retainable {
private:
    CONSTRUCT_VIA_MAKE_RETAIN;  // 允许 MakeRetain 访问私有构造函数
    SecretDoc() {}              // 私有构造函数
};

💡 最佳实践和常见模式

1. 函数参数传递

// 推荐:const 引用传递(不增加计数)
void ReadDocument(const RetainPtr<Document>& doc);

// 需要共享所有权时:值传递(增加计数)
void StoreDocument(RetainPtr<Document> doc);

// 不推荐:原始指针传递(失去所有权管理)
void RiskyFunction(Document* doc);

2. 容器使用

// 在 vector 中存储智能指针
std::vector<RetainPtr<Document>> documents;

// 添加文档
documents.push_back(MakeRetain<Document>("Doc1"));
documents.emplace_back(new Document("Doc2"));

// 安全遍历
for (const auto& doc : documents) {
    doc->Process();
}

3. 多态使用

class Shape : public Retainable {
public:
    virtual void Draw() = 0;
};

class Circle : public Shape {
public:
    void Draw() override { /*...*/ }
};

// 多态容器
std::vector<RetainPtr<Shape>> shapes;
shapes.push_back(MakeRetain<Circle>());

4. 循环引用处理

class Node : public Retainable {
public:
    void SetParent(const RetainPtr<Node>& parent) {
        m_parent = parent;  // 强引用 → 可能循环引用
    }
    
    void SetWeakParent(const RetainPtr<Node>& parent) {
        m_weakParent = parent.Get();  // 弱引用打破循环
    }

private:
    RetainPtr<Node> m_parent;        // 强引用
    Node* m_weakParent = nullptr;    // 弱引用
};

⚠️ 注意事项和陷阱

陷阱 问题描述 解决方案
循环引用 对象相互持有强引用,无法释放 使用弱引用或原始指针
混用 new/Delete 手动管理 RetainPtr 管理的对象 始终使用 MakeRetain
跨 DLL 边界 不同模块中的 new/delete 不匹配 确保统一的分配器
线程安全 非原子操作引用计数 需要外部同步机制

🎯 完整使用示例

// 定义可保留对象
class DatabaseConnection : public Retainable {
public:
    static RetainPtr<DatabaseConnection> Create(const std::string& url) {
        return MakeRetain<DatabaseConnection>(url);
    }
    
    void Query(const std::string& sql) {
        std::cout << "Executing: " << sql << std::endl;
    }
    
    ~DatabaseConnection() override {
        std::cout << "Connection closed" << std::endl;
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;
    DatabaseConnection(const std::string& url) : m_url(url) {
        std::cout << "Connection opened to: " << url << std::endl;
    }
    
    std::string m_url;
};

// 使用示例
void Demo() {
    // 创建连接
    auto conn = DatabaseConnection::Create("mysql://localhost");
    
    // 传递到函数
    ExecuteQuery(conn);
    
    // 在容器中存储
    std::vector<RetainPtr<DatabaseConnection>> connections;
    connections.push_back(conn);
    
    // 类型转换示例
    RetainPtr<Retainable> base = conn.As<Retainable>();
}

这个全面的介绍应该帮助你深入理解 RetainPtr 系统的设计理念、实现细节和最佳实践用法。

创建方式的限制

错误代码如下

#pragma once
#include "retain_ptr.h"
#include <iostream>
#include <vector>
#include <string>
using std::string;

// 示例1: 继承自 Retainable 的类
class Document : public fxcrt::Retainable {
public:
    explicit Document(const std::string& title) : m_title(title) {
        std::cout << "Document created: " << m_title << std::endl;
    }

    ~Document() override {
        std::cout << "Document destroyed: " << m_title << std::endl;
    }

    void SetTitle(const std::string& title) { m_title = title; }
    const std::string& GetTitle() const { return m_title; }

    void Print() const {
        std::cout << "Document: " << m_title
            << " (Refs: " << (HasOneRef() ? "1" : ">1") << ")" << std::endl;
    }

private:
    std::string m_title;
};

// 示例2: 另一个可保留的类
class Page : public fxcrt::Retainable {
public:
    explicit Page(int number) : m_number(number) {
        std::cout << "Page created: " << m_number << std::endl;
    }

    ~Page() override {
        std::cout << "Page destroyed: " << m_number << std::endl;
    }

    int GetNumber() const { return m_number; }

private:
    int m_number;
};

// 示例3: 使用私有构造函数的类
class SecretDocument : public fxcrt::Retainable {
public:
    static fxcrt::RetainPtr<SecretDocument> Create(const std::string& content) {
        return fxcrt::MakeRetain<SecretDocument>(content);
    }

    const std::string& GetContent() const { return m_content; }

    void Reveal() const {
        std::cout << "Secret content: " << m_content << std::endl;
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;

    explicit SecretDocument(const std::string& content) : m_content(content) {
        std::cout << "SecretDocument created" << std::endl;
    }

    ~SecretDocument() override {
        std::cout << "SecretDocument destroyed" << std::endl;
    }

    std::string m_content;
};

// 函数示例:演示参数传递和返回值
fxcrt::RetainPtr<Document> CreateDocument(const std::string& title) {
    return fxcrt::MakeRetain<Document>(title);
}

void ProcessDocument(const fxcrt::RetainPtr<Document>& doc) {
    if (doc) {
        std::cout << "Processing: " << doc->GetTitle() << std::endl;
        doc->Print();
    }
}

void ModifyDocument(fxcrt::RetainPtr<Document> doc) {
    if (doc) {
        doc->SetTitle("Modified " + doc->GetTitle());
    }
}

// 演示容器使用
void DemonstrateContainers() {
    std::vector<fxcrt::RetainPtr<Page>> pages;

    // 添加页面
    for (int i = 1; i <= 3; ++i) {
        pages.push_back(fxcrt::MakeRetain<Page>(i));
    }

    std::cout << "Created " << pages.size() << " pages" << std::endl;
}

int main() {
    std::cout << "=== 开始 RetainPtr 演示 ===" << std::endl;

    // 1. 基本用法
    {
        std::cout << "\n1. 基本创建和销毁:" << std::endl;
        auto doc = fxcrt::MakeRetain<Document>("Test Document");
        doc->Print();
    } // doc 超出作用域,自动销毁

    // 2. 多引用计数
    {
        std::cout << "\n2. 多引用计数演示:" << std::endl;
        auto original = fxcrt::MakeRetain<Document>("Shared Document");
        original->Print();

        // 创建另一个引用
        fxcrt::RetainPtr<Document> copy = original;
        copy->Print(); // 引用计数应为2

        // 重置一个引用
        copy.Reset();
        original->Print(); // 引用计数回到1
    }

    // 3. 函数参数和返回值
    {
        std::cout << "\n3. 函数传递演示:" << std::endl;
        auto doc = CreateDocument("Function Document");
        ProcessDocument(doc);
        ModifyDocument(doc); // 值传递,创建新引用
        ProcessDocument(doc); // 原文档未改变
    }

    // 4. 类型转换
    {
        std::cout << "\n4. 类型转换演示:" << std::endl;
        auto doc = fxcrt::MakeRetain<Document>("Cast Document");

        // 隐式转换为原始指针
        Document* rawPtr = doc;
        std::cout << "Raw pointer: " << rawPtr->GetTitle() << std::endl;

        // 显式获取原始指针
        Document* explicitPtr = doc.Get();
        std::cout << "Explicit pointer: " << explicitPtr->GetTitle() << std::endl;
    }

    // 5. 比较操作
    {
        std::cout << "\n5. 比较操作演示:" << std::endl;
        auto doc1 = fxcrt::MakeRetain<Document>("Doc 1");
        auto doc2 = fxcrt::MakeRetain<Document>("Doc 2");
        auto doc1Copy = doc1;

        std::cout << "doc1 == doc1Copy: " << (doc1 == doc1Copy) << std::endl;
        std::cout << "doc1 == doc2: " << (doc1 == doc2) << std::endl;
        std::cout << "doc1 != nullptr: " << (doc1 != nullptr) << std::endl;
    }

    // 6. 移动语义
    {
        std::cout << "\n6. 移动语义演示:" << std::endl;
        auto doc = fxcrt::MakeRetain<Document>("Movable Document");

        // 移动构造
        fxcrt::RetainPtr<Document> movedDoc = std::move(doc);
        std::cout << "After move, original is null: " << (doc == nullptr) << std::endl;
        movedDoc->Print();

        // 移动赋值
        doc = std::move(movedDoc);
        std::cout << "After move back, moved is null: " << (movedDoc == nullptr) << std::endl;
        doc->Print();
    }

    // 7. 私有构造函数类
    {
        std::cout << "\n7. 私有构造函数演示:" << std::endl;
        auto secret = SecretDocument::Create("Top Secret");
        secret->Reveal();
    }

    // 8. 容器使用
    {
        std::cout << "\n8. 容器使用演示:" << std::endl;
        DemonstrateContainers();
    }

    // 9. 复杂场景:对象关系
    {
        /*std::cout << "\n9. 对象关系演示:" << std::endl;
        class Book : public fxcrt::Retainable {
        public:
            static fxcrt::RetainPtr<Book> Create(const std::string& title) {
                return fxcrt::MakeRetain<Book>(title);
            }

            void AddChapter(const fxcrt::RetainPtr<Document>& chapter) {
                m_chapters.push_back(chapter);
            }

            void Print() const {
                std::cout << "Book: " << m_title
                    << " (" << m_chapters.size() << " chapters)" << std::endl;
                for (const auto& chapter : m_chapters) {
                    std::cout << "  - " << chapter->GetTitle() << std::endl;
                }
            }

        private:
            CONSTRUCT_VIA_MAKE_RETAIN;

            explicit Book(const std::string& title) : m_title(title) {}

            std::string m_title;
            std::vector<fxcrt::RetainPtr<Document>> m_chapters;
        };

        auto book = Book::Create("My Book");
        book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 1"));
        book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 2"));
        book->Print();*/
    }

    std::cout << "\n=== RetainPtr 演示结束 ===" << std::endl;
    return 0;
}

🔍 RetainPtr 构造函数限制分析

你遇到的错误是因为 RetainPtr 系统有严格的访问控制机制。让我详细解释为什么直接使用构造函数是错误的:

🚫 问题根源:CONSTRUCT_VIA_MAKE_RETAIN 宏的限制

宏定义分析

#define CONSTRUCT_VIA_MAKE_RETAIN         \
  template <typename T, typename... Args> \
  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args)

这个宏只授予了 pdfium::MakeRetain 函数模板访问私有构造函数的权限,但没有授予其他任何函数或类访问权限

错误场景分析

class Book : public fxcrt::Retainable {
private:
    CONSTRUCT_VIA_MAKE_RETAIN;
    explicit Book(const std::string& title) : m_title(title) {} // 私有构造函数
};

// 以下都是错误的:
auto book1 = new Book("My Book");                    // ❌ 错误:构造函数私有
auto book2 = Book("My Book");                        // ❌ 错误:构造函数私有  
auto book3 = fxcrt::RetainPtr<Book>(new Book("My Book")); // ❌ 错误:构造函数私有

✅ 唯一正确的创建方式

1. 使用静态工厂方法(推荐)

class Book : public fxcrt::Retainable {
public:
    static fxcrt::RetainPtr<Book> Create(const std::string& title) {
        return fxcrt::MakeRetain<Book>(title); // ✅ 正确:通过友元函数访问
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;
    explicit Book(const std::string& title) : m_title(title) {}
};

// 使用:
auto book = Book::Create("My Book"); // ✅ 正确

2. 直接使用 MakeRetain(如果可见)

auto book = fxcrt::MakeRetain<Book>("My Book"); // ✅ 正确(但需要MakeRetain可见)

🛠️ 修复你的代码

修改 Book 类的定义:

class Book : public fxcrt::Retainable {
public:
    // 添加静态工厂方法
    static fxcrt::RetainPtr<Book> Create(const std::string& title) {
        return fxcrt::MakeRetain<Book>(title);
    }

    void AddChapter(const fxcrt::RetainPtr<Document>& chapter) {
        m_chapters.push_back(chapter);
    }

    void Print() const {
        std::cout << "Book: " << m_title
            << " (" << m_chapters.size() << " chapters)" << std::endl;
        for (const auto& chapter : m_chapters) {
            std::cout << "  - " << chapter->GetTitle() << std::endl;
        }
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;
    explicit Book(const std::string& title) : m_title(title) {}

    std::string m_title;
    std::vector<fxcrt::RetainPtr<Document>> m_chapters;
};

修改使用代码:

// 9. 复杂场景:对象关系
{
    std::cout << "\n9. 对象关系演示:" << std::endl;
    
    // 使用工厂方法创建,而不是直接构造
    auto book = Book::Create("My Book");
    book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 1"));
    book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 2"));
    book->Print();
}

📋 访问权限总结表

创建方式 访问权限 是否可行 说明
new Book() 需要访问私有构造函数 ❌ 失败 构造函数私有
Book::Create() 通过友元 MakeRetain 访问 ✅ 成功 推荐方式
MakeRetain<Book>() 友元函数直接访问 ✅ 成功 需要函数可见
RetainPtr<Book>(new Book()) 需要访问私有构造函数 ❌ 失败 双重错误

🎯 设计意图理解

这种设计模式有几个重要目的:

  1. 强制使用智能指针:防止用户使用原始指针或栈对象
  2. 控制对象创建:确保所有对象都被 RetainPtr 正确管理
  3. 接口清晰:通过工厂方法提供明确的创建接口
  4. 防止误用:避免手动管理内存和潜在的内存泄漏

💡 完整修正后的代码

// 9. 复杂场景:对象关系
{
    std::cout << "\n9. 对象关系演示:" << std::endl;
    
    class Book : public fxcrt::Retainable {
    public:
        static fxcrt::RetainPtr<Book> Create(const std::string& title) {
            return fxcrt::MakeRetain<Book>(title);
        }

        void AddChapter(const fxcrt::RetainPtr<Document>& chapter) {
            m_chapters.push_back(chapter);
        }

        void Print() const {
            std::cout << "Book: " << m_title
                << " (" << m_chapters.size() << " chapters)" << std::endl;
            for (const auto& chapter : m_chapters) {
                std::cout << "  - " << chapter->GetTitle() << std::endl;
            }
        }

    private:
        CONSTRUCT_VIA_MAKE_RETAIN;
        explicit Book(const std::string& title) : m_title(title) {}

        std::string m_title;
        std::vector<fxcrt::RetainPtr<Document>> m_chapters;
    };

    auto book = Book::Create("My Book");
    book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 1"));
    book->AddChapter(fxcrt::MakeRetain<Document>("Chapter 2"));
    book->Print();
}

这种设计模式确保了类型安全性和内存安全性,是大型C++项目中常见的最佳实践。

修正的完整代码(正确构造对象)

#pragma once
#include "retain_ptr.h"
#include <iostream>
#include <vector>
#include <string>
using std::string;

// 示例1: 继承自 Retainable 的类
class Document : public fxcrt::Retainable {
public:
    explicit Document(const std::string& title) : m_title(title) {
        std::cout << "Document created: " << m_title << std::endl;
    }

    ~Document() override {
        std::cout << "Document destroyed: " << m_title << std::endl;
    }

    void SetTitle(const std::string& title) { m_title = title; }
    const std::string& GetTitle() const { return m_title; }

    void Print() const {
        std::cout << "Document: " << m_title
            << " (Refs: " << (HasOneRef() ? "1" : ">1") << ")" << std::endl;
    }

private:
    std::string m_title;
};

// 示例2: 另一个可保留的类
class Page : public fxcrt::Retainable {
public:
    explicit Page(int number) : m_number(number) {
        std::cout << "Page created: " << m_number << std::endl;
    }

    ~Page() override {
        std::cout << "Page destroyed: " << m_number << std::endl;
    }

    int GetNumber() const { return m_number; }

private:
    int m_number;
};

// 示例3: 使用私有构造函数的类
class SecretDocument : public fxcrt::Retainable {
public:
    static fxcrt::RetainPtr<SecretDocument> Create(const std::string& content) {
        return pdfium::MakeRetain<SecretDocument>(content);
    }

    const std::string& GetContent() const { return m_content; }

    void Reveal() const {
        std::cout << "Secret content: " << m_content << std::endl;
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;

    explicit SecretDocument(const std::string& content) : m_content(content) {
        std::cout << "SecretDocument created" << std::endl;
    }

    ~SecretDocument() override {
        std::cout << "SecretDocument destroyed" << std::endl;
    }

    std::string m_content;
};

// 函数示例:演示参数传递和返回值
fxcrt::RetainPtr<Document> CreateDocument(const std::string& title) {
    return pdfium::MakeRetain<Document>(title);
}

void ProcessDocument(const fxcrt::RetainPtr<Document>& doc) {
    if (doc) {
        std::cout << "Processing: " << doc->GetTitle() << std::endl;
        doc->Print();
    }
}

void ModifyDocument(fxcrt::RetainPtr<Document> doc) {
    if (doc) {
        doc->SetTitle("Modified " + doc->GetTitle());
    }
}

// 演示容器使用
void DemonstrateContainers() {
    std::vector<fxcrt::RetainPtr<Page>> pages;

    // 添加页面
    for (int i = 1; i <= 3; ++i) {
        pages.push_back(pdfium::MakeRetain<Page>(i));
    }

    std::cout << "Created " << pages.size() << " pages" << std::endl;
}


class Book : public fxcrt::Retainable {
public:
    static fxcrt::RetainPtr<Book> Create(const std::string& title) {
        return pdfium::MakeRetain<Book>(title);
    }

    void AddChapter(const fxcrt::RetainPtr<Document>& chapter) {
        m_chapters.push_back(chapter);
    }

    void Print() const {
        std::cout << "Book: " << m_title
            << " (" << m_chapters.size() << " chapters)" << std::endl;
        for (const auto& chapter : m_chapters) {
            std::cout << "  - " << chapter->GetTitle() << std::endl;
        }
    }

private:
    CONSTRUCT_VIA_MAKE_RETAIN;

    explicit Book(const std::string& title) : m_title(title) {}

    std::string m_title;
    std::vector<fxcrt::RetainPtr<Document>> m_chapters;
};

int main() {
    std::cout << "=== 开始 RetainPtr 演示 ===" << std::endl;

    // 1. 基本用法
    {
        std::cout << "\n1. 基本创建和销毁:" << std::endl;
        auto doc = pdfium::MakeRetain<Document>("Test Document");
        doc->Print();
    } // doc 超出作用域,自动销毁

    // 2. 多引用计数
    {
        std::cout << "\n2. 多引用计数演示:" << std::endl;
        auto original = pdfium::MakeRetain<Document>("Shared Document");
        original->Print();

        // 创建另一个引用
        fxcrt::RetainPtr<Document> copy = original;
        copy->Print(); // 引用计数应为2

        // 重置一个引用
        copy.Reset();
        original->Print(); // 引用计数回到1
    }

    // 3. 函数参数和返回值
    {
        std::cout << "\n3. 函数传递演示:" << std::endl;
        auto doc = CreateDocument("Function Document");
        ProcessDocument(doc);
        ModifyDocument(doc); // 值传递,创建新引用
        ProcessDocument(doc); // 原文档未改变
    }

    // 4. 类型转换
    {
        std::cout << "\n4. 类型转换演示:" << std::endl;
        auto doc = pdfium::MakeRetain<Document>("Cast Document");

        // 隐式转换为原始指针
        Document* rawPtr = doc;
        std::cout << "Raw pointer: " << rawPtr->GetTitle() << std::endl;

        // 显式获取原始指针
        Document* explicitPtr = doc.Get();
        std::cout << "Explicit pointer: " << explicitPtr->GetTitle() << std::endl;
    }

    // 5. 比较操作
    {
        std::cout << "\n5. 比较操作演示:" << std::endl;
        auto doc1 = pdfium::MakeRetain<Document>("Doc 1");
        auto doc2 = pdfium::MakeRetain<Document>("Doc 2");
        auto doc1Copy = doc1;

        std::cout << "doc1 == doc1Copy: " << (doc1 == doc1Copy) << std::endl;
        std::cout << "doc1 == doc2: " << (doc1 == doc2) << std::endl;
        std::cout << "doc1 != nullptr: " << (doc1 != nullptr) << std::endl;
    }

    // 6. 移动语义
    {
        std::cout << "\n6. 移动语义演示:" << std::endl;
        auto doc = pdfium::MakeRetain<Document>("Movable Document");

        // 移动构造
        fxcrt::RetainPtr<Document> movedDoc = std::move(doc);
        std::cout << "After move, original is null: " << (doc == nullptr) << std::endl;
        movedDoc->Print();

        // 移动赋值
        doc = std::move(movedDoc);
        std::cout << "After move back, moved is null: " << (movedDoc == nullptr) << std::endl;
        doc->Print();
    }

    // 7. 私有构造函数类
    {
        std::cout << "\n7. 私有构造函数演示:" << std::endl;
        auto secret = SecretDocument::Create("Top Secret");
        secret->Reveal();
    }

    // 8. 容器使用
    {
        std::cout << "\n8. 容器使用演示:" << std::endl;
        DemonstrateContainers();
    }

    // 9. 复杂场景:对象关系
    {
        std::cout << "\n9. 对象关系演示:" << std::endl;
       

        auto book = Book::Create("My Book");
        book->AddChapter(pdfium::MakeRetain<Document>("Chapter 1"));
        book->AddChapter(pdfium::MakeRetain<Document>("Chapter 2"));
        book->Print();
    }

    std::cout << "\n=== RetainPtr 演示结束 ===" << std::endl;
    return 0;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐