【问题标题】:Where should the objects created by a factory method be deleted?工厂方法创建的对象应该在哪里删除?
【发布时间】:2018-06-18 05:37:12
【问题描述】:

returnShapeType 创建的对象应该如何以及在哪里被删除?
这是一个工厂方法演示程序。

请出示代码。

class Shape
{
public:
    Shape() {}
    virtual void print() {std::cout << "\nFrom shape print";}
};

class Triangle: public Shape
{
public:
    Triangle(){}
    virtual void print() {std::cout << "\nFrom triangle print";}
};

class Rectangle: public Shape
{
public:
    Rectangle(){}
    virtual void print() {std::cout << "\nFrom rect print";}
};

class CreateShapeObject
{
public:
    CreateShapeObject() {}

    Shape *returnShapeType( std::string arg )
    {
        if (arg == "Triangle")
            return new Triangle;
        else if (arg == "Rectangle")
            return new Rectangle;
    }
};

////////////

class EndDeveloper
{
public:
    CreateShapeObject obj;

    EndDeveloper()
    {
        Shape *p = obj.returnShapeType("Triangle");
        p->print();

        Shape *q = obj.returnShapeType("Rectangle");
        q->print();


    }
};

【问题讨论】:

  • “在哪里”是什么意思?什么时候?执行它的代码应该在哪里(在哪个类中)?
  • 最好的策略是通过不返回需要手动删除的内容来使问题变得毫无意义。智能指针是一个经常使用的糟糕解决方案。但是您可以将动态分配的对象包装在您自己的类型中,自动管理资源。
  • @juanchopanza 你能详细说明“糟糕的解决方案”吗?例如,我没有看到返回唯一指针的问题?
  • @andreee 还是一个指针,有指针和引用语义。
  • @juanchopanza “但是您可以将动态分配的对象包装在您自己的类型中,自动管理资源。”请在答案中举例说明。

标签: c++ design-patterns factory factory-pattern


【解决方案1】:

使用原始指针容易出错。使用unique_ptr:

std::unique_ptr<Shape> returnShapeType(const std::string& arg)
{
    if (arg == "Triangle")
        return std::make_unique<Triangle>();
    else if (arg == "Rectangle")
        return std::make_unique<Rectangle>();
    throw std::invalid_argument("Invalid shape");
}

您可以通过auto方便地使用它:

auto shape = obj.returnShapeType("Triangle");

unique_ptr也可以隐式转换为shared_ptr

std::shared_ptr<Shape> shape = obj.returnShapeType("Triangle");

【讨论】:

  • 唯一指针也是词汇类型。它具有明显的优势,就在函数的签名中:“此指针没有其他句柄”。这是关于所有权的强烈而明确的信息,IMO。它确实应该是默认选择。
  • 我建议把arg 当作std::string_view
  • @StoryTeller 但是,如果您想要的只是多态性,这仍然是错误的。使用它是因为 C++ 没有更好的开箱即用替代方案。多态性不应该受限于唯一所有权和共享所有权之间的选择。这应该是一个正交问题。
  • @juanchopanza - 我真的不知道你在说什么,抱歉。当你想要“只是多态性”时它是“错误的”,但是没有“只是多态性”?对于不存在的选项,它不能是错误的选择。必须有人管理对象的生命周期。这是最好的默认选择。
  • @StoryTeller 更好的选择是将内存管理隐藏在具有值语义的多态类型中。这将多态性与唯一与共享所有权的不相关选择分离。
【解决方案2】:

您必须在设计中建立所有权原则。

在您发布的代码中,CreateShapeObject 不保留指向已构造对象的指针。它只是返回一个指向构造对象的指针。这意味着调用函数/类必须拥有对象的所有权。他们应该负责删除它,除非他们将所有权传递给另一个函数/类,在这种情况下,另一个函数/类应该负责删除它。

如果您想让CreateShapeObject 负责删除它构造的对象,则必须更新它以跟踪它构造的对象。此时,您可能希望更改类的名称以反映双重责任。类似ShapeObjectManager 的东西会更有意义。

【讨论】:

    【解决方案3】:

    通过工厂处理 new 的任何使用,就像对待 new 的任何其他使用一样。
    IE。使用new(通过工厂与否)的代码/类也负责执行delete

    【讨论】:

    • 该函数不返回任何我可以在析构函数中获取和删除的变量。如何删除“返回新三角形”?
    • “那个功能”是指Shape *returnShapeType( std::string arg )?我很迷惑。 “不返回任何变量”是什么意思?它不应该返回一个变量,它返回一个指向新创建的对象的指针。该指针就是删除创建的对象所需的全部内容。
    • 这是否意味着我应该这样写:delete p 其中 p 是最终用户类的构造函数中的 Shape 指针?
    • 仅当您不打算使用构造函数之后的对象时。这似乎有点奇怪。如果您的意思是“析构函数”,那么是的,如果父对象的析构是您知道不再使用该对象的时候,那将是一个如何做的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多