C++ 静态工厂方法与构造函数 : how to avoid copying?

标签 c++ oop

This question要求以简洁的方式在 C++ 中实现静态工厂方法,this answer描述了一种明确的方法。返回值优化将使我们免于制作不必要的 Object 拷贝,从而使这种创建 Object 的方式与直接调用构造函数一样高效。在私有(private)构造函数中将 i 复制到 id 的开销可以忽略不计,因为它是一个小的 int

但是,当 Object 包含作为类 Foo 实例的实例变量(需要复杂的初始化逻辑)时,问题和答案并未涵盖更复杂的情况) 而不是一个小的原始类型。假设我想使用传递给 Object 的参数构造 Foo。使用构造函数的解决方案如下所示:

class Object {
    Foo foo;

public:
    Object(const FooArg& fooArg) {
        // Create foo using fooArg here
        foo = ...
    }
}

在我看来,与引用的答案类似的静态工厂方法的替代方法是:

class Object {
    Foo foo;

    explicit Object(const Foo& foo_):
        foo(foo_)
    {

    }

public:
    static Object FromFooArg(const FooArg& fooArg) {
        // Create foo using fooArg here
        Foo foo = ...
        return Object(foo);
    }
}

在这里,将 foo_ 复制到 foo 的开销不再一定可以忽略不计,因为 Foo 可以是任意复杂的类。此外,据我了解(这里是 C++ 新手,所以我可能错了),这段代码隐含地要求为 Foo 定义一个复制构造函数。

在这种情况下,什么是实现这种模式的类似干净但有效的方法?

为了预测关于为什么这是相关的可能问题,我考虑让构造函数具有比仅仅复制参数更复杂的逻辑作为反模式。我希望构造函数:

  • 保证工作正常,不抛出异常,
  • 不要在后台进行繁重的计算。

因此,我更喜欢将复杂的初始化逻辑放入静态方法中。此外,这种方法提供了额外的好处,例如即使输入参数类型相同,也可以通过静态工厂方法名称进行重载,并且可以清楚地以方法名称说明内部正在执行的操作。

最佳答案

感谢移动构造函数,您可能会这样做:

class Object {
    Foo foo;

    explicit Object(Foo&& foo_) : foo(std::move(foo_)) {}

public:
    static Object FromFooArg(const FooArg& fooArg) {
        // Create foo using fooArg here
        Foo foo = ...
        return Object(std::move(foo));
    }
};

如果 Foo 不可移动,则可以将其包装在智能指针中:

class Object {
    std::unique_ptr<Foo> foo;

    explicit Object(std::unique_ptr<Foo>&& foo_) : foo(std::move(foo_)) {}

public:
    static Object FromFooArg(const FooArg& fooArg) {
        // Create foo using fooArg here
        std::unique_ptr<Foo> foo = ...
        return Object(std::move(foo));
    }
};

关于C++ 静态工厂方法与构造函数 : how to avoid copying?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50941946/

相关文章:

c++ - 左值需要作为赋值的左操作数(递增引用的变量)C++

c++ - 对静态库中类变量的 undefined reference

c++ - 在顶层使用 shared_ptr 而不是 scoped_ptr 有什么优势吗?

c++ - 如何停止循环线程

javascript - 'var a = b' 和 'this.a = b' 之间的区别

c++ - 函数参数的多态性

string - 在 valgrind 中读取和写入大小无效

java - 当 'ACE' 牌出现在我的二十一点游戏手中时,我的算法出现问题

c# - 从父类继承而无需重新实现父类的子类接口(interface)

c++ - 模板特化,其中参数是用于元编程的非类型参数化模板