【问题标题】:Factory method creating shared_ptr object工厂方法创建 shared_ptr 对象
【发布时间】:2014-09-24 22:24:50
【问题描述】:

当使用工厂创建对象时,例如在下面的示例中,在某些情况下,shared_ptr 包裹的对象在返回过程中显然会被删除(在调试过程中对象创建正常但分配时到this->xs 抛出异常)。当我将工厂方法更改为返回原始指针并将Link::xs 成员更改为unique_ptr 时,代码运行良好。 shared_ptr 的底层发生了什么导致它以这种方式运行?这与shared_ptr<CrossSection> 包装Circular 对象的事实有关吗?已使用 MS Visual C++ 2012 完成测试。

class Link
{
private:
    std::shared_ptr<xs::CrossSection> xs;
public:
    void parseXsection(const std::vector<std::string>& parts);
    std::shared_ptr<xs::CrossSection> getXs() { return this->xs; }
};
void Link::parseXsection(const std::vector<std::string>& parts)
{
    this->xs = xs::Factory::create(parts[1]);
}

namespace xs
{
    class CrossSection
    {
    };
    class Circular : public CrossSection
    {
    };
    class Dummy : public CrossSection
    {
    };
    class Factory
    {
    public:
        static std::shared_ptr<CrossSection> create(const std::string& type);
    };
    std::shared_ptr<CrossSection> Factory::create(const std::string& type)
    {
        if (geom == "circular")
        {
            return std::shared_ptr<CrossSection>(new Circular());
        }
        else
        {
            return std::shared_ptr<CrossSection>(new Dummy());
        }
    }
}

【问题讨论】:

  • 您的代码具有未定义的行为,因为Factory::create 在必须返回 shared_ptr 时可能不会返回任何内容。你应该先解决这个问题。
  • 我添加了更多代码来解决这个问题,但在我的实际实现中已经处理好了。
  • 我确信这只是为了简单起见,但总的来说,使用枚举类型和switch 语句来做类似的事情可能是一个更好的主意。它比进行字符串比较更有效,并且您可以在一个地方修改所有比较选项。

标签: c++ visual-c++ polymorphism shared-ptr


【解决方案1】:

因此,Martin 有一个解决析构函数问题的选项。您可以添加一个虚拟析构函数。

但是,由于您使用的是std::shared_ptr,它采用了一些类型擦除,您可以做一个较小的修复:

std::shared_ptr<CrossSection> Factory::create(const std::string& type)
{
    if (geom == "circular")
        return std::shared_ptr<Circular>(new Circular());
    else
        return std::shared_ptr<Dummy>(new Dummy());
}

或者,甚至更好:

std::shared_ptr<CrossSection> Factory::create(const std::string& type)
{
    if (geom == "circular")
        return std::make_shared<Circular>();
    else
        return std::make_shared<Dummy>();
}

【讨论】:

  • 这比在CrossSection 中拥有一个虚拟析构函数有什么帮助?
  • @RSahu:它有同样的帮助。您知道shared_ptr 第一次构造时将保留原始指针类型的知识,并调用该析构函数。所以在这里,只要原来的 shared_ptr 构造函数有正确的类型(这就是我的改变的全部内容),那么正确的析构函数就会被调用
  • 不,我不知道shared_ptr保留了原始指针类型的知识。 +1。
  • @RSahu This post 对其工作原理进行了合理的解释。
【解决方案2】:

为了使用多态性,你肯定需要在你的CrossSection 基类中定义一个虚拟析构函数,即为了声明派生类并使用它们代替父类(所以通常几乎每次你想使用派生类...)

class CrossSection {
  public:
    virtual ~CrossSection() { /* Nothing to do here ... */ }
};

参见例如When to use virtual destructors?Should every class have a virtual destructor? 以获得更多解释。

PS:我现在不能说,如果这是您使用 shared_ptr 问题的原因,但它看起来很像您忘记虚拟析构函数时可能遇到的那种问题...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    相关资源
    最近更新 更多