You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用智能指针实现C++建造者设计模式?

用智能指针实现C++建造者模式的现代版本

智能指针选择核心逻辑

  • std::unique_ptr:优先用于独占所有权的场景,比如建造者创建的产品——默认情况下,产品的所有权应该由建造者转移给调用方,不需要多组件共享,unique_ptr的移动语义刚好适配这种所有权转移需求。
  • std::shared_ptr:仅当你需要多个组件长期持有同一个产品实例时才使用,比如多个业务模块需要同时访问产品且生命周期不一致,否则没必要用(会带来额外的引用计数开销)。
  • 传递规则:
    • 转移所有权:用std::unique_ptr<T>&&(右值引用)或直接返回unique_ptr<T>,调用时用std::move()转移。
    • 临时访问:如果只是需要读取产品/建造者的状态,用const T&或者非拥有的裸指针(T*)即可,不需要传递智能指针。

改造后的完整代码

基于你参考的建造者模式示例,以下是适配智能指针的现代C++实现:

#include <iostream>
#include <memory>
#include <vector>
#include <string>

// 产品类:和原示例逻辑一致,只是不再通过裸指针返回
class Product {
public:
    std::vector<std::string> parts_;
    void ListParts() const {
        std::cout << "Product parts: ";
        for (size_t i = 0; i < parts_.size(); ++i) {
            if (parts_[i] == parts_.back()) {
                std::cout << parts_[i];
            } else {
                std::cout << parts_[i] << ", ";
            }
        }
        std::cout << "\n\n";
    }
};

// 抽象建造者:修改GetResult返回unique_ptr
class Builder {
public:
    virtual ~Builder() = default;
    virtual void ProducePartA() = 0;
    virtual void ProducePartB() = 0;
    virtual void ProducePartC() = 0;
    virtual std::unique_ptr<Product> GetResult() = 0;
};

// 具体建造者:用unique_ptr管理产品实例
class ConcreteBuilder1 : public Builder {
private:
    std::unique_ptr<Product> product_ = std::make_unique<Product>();
public:
    // 重置产品实例,准备创建新对象
    void Reset() {
        product_ = std::make_unique<Product>();
    }

    void ProducePartA() override {
        product_->parts_.push_back("PartA1");
    }

    void ProducePartB() override {
        product_->parts_.push_back("PartB1");
    }

    void ProducePartC() override {
        product_->parts_.push_back("PartC1");
    }

    // 转移产品所有权给调用方,调用后建造者不再持有该产品
    std::unique_ptr<Product> GetResult() override {
        return std::move(product_);
    }
};

// 指挥者:不需要持有任何智能指针,只需要引用建造者即可
class Director {
private:
    Builder* builder_ = nullptr;
public:
    void set_builder(Builder* builder) {
        builder_ = builder;
    }

    // 构建不同配置的产品
    void BuildMinimalViableProduct() {
        builder_->ProducePartA();
    }

    void BuildFullFeaturedProduct() {
        builder_->ProducePartA();
        builder_->ProducePartB();
        builder_->ProducePartC();
    }
};

// 客户端代码
int main() {
    Director director;
    ConcreteBuilder1 builder;
    director.set_builder(&builder);

    std::cout << "Standard basic product:\n";
    director.BuildMinimalViableProduct();
    auto product1 = builder.GetResult();
    product1->ListParts();

    // 重置建造者,创建新产品
    builder.Reset();

    std::cout << "Standard full featured product:\n";
    director.BuildFullFeaturedProduct();
    auto product2 = builder.GetResult();
    product2->ListParts();

    // 不需要手动delete,智能指针自动管理生命周期
    return 0;
}

关键改造点说明

  1. 产品所有权转移:ConcreteBuilder1的GetResult()通过std::move()转移unique_ptr的所有权,调用方拿到产品后完全拥有它,建造者不再持有,避免了裸指针的内存泄漏风险。
  2. 建造者的生命周期:客户端直接创建具体建造者的栈实例,不需要用智能指针——因为客户端是建造者的所有者,指挥者只是临时使用它,不需要持有所有权。如果需要动态创建建造者(比如基于配置选择不同建造者),可以用std::unique_ptr<Builder>来管理。
  3. 何时用shared_ptr?:如果你的业务场景中,比如多个Director或者其他组件需要同时持有同一个Product实例,且生命周期不一致,那可以把unique_ptr换成shared_ptr,GetResult()返回shared_ptr<Product>,此时建造者和调用方共享所有权。

内容的提问来源于stack exchange,提问作者WolfyDoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:05:00