Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/164.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;静态工厂方法与构造函数:如何避免复制? 要求在C++中实现一个干净的工厂方法,并描述了一个明确的方法。返回值优化将使我们不必复制对象,从而使这种创建对象的方法与直接调用构造函数一样高效。在私有构造函数内将i复制到id的开销可以忽略,因为它是一个小的int_C++_Oop - Fatal编程技术网

C++;静态工厂方法与构造函数:如何避免复制? 要求在C++中实现一个干净的工厂方法,并描述了一个明确的方法。返回值优化将使我们不必复制对象,从而使这种创建对象的方法与直接调用构造函数一样高效。在私有构造函数内将i复制到id的开销可以忽略,因为它是一个小的int

C++;静态工厂方法与构造函数:如何避免复制? 要求在C++中实现一个干净的工厂方法,并描述了一个明确的方法。返回值优化将使我们不必复制对象,从而使这种创建对象的方法与直接调用构造函数一样高效。在私有构造函数内将i复制到id的开销可以忽略,因为它是一个小的int,c++,oop,C++,Oop,但是,当对象包含一个实例变量,该实例变量是类Foo(需要复杂的初始化逻辑)的实例,而不是一个小的基元类型时,问题和答案不会涉及更复杂的情况。假设我想使用传递给对象的参数来构造Foo。使用构造函数的解决方案类似于: class Object { Foo foo; public: Object(const FooArg& fooArg) { // Create foo using fooArg here foo = ... } }

但是,当
对象
包含一个实例变量,该实例变量是类
Foo
(需要复杂的初始化逻辑)的实例,而不是一个小的基元类型时,问题和答案不会涉及更复杂的情况。假设我想使用传递给
对象的参数来构造
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
定义一个复制构造函数

在这种情况下,实现这种模式的同样干净但又有效的方法是什么

为了预想为什么这是相关的问题,我认为构造函数逻辑更复杂,而不仅仅是复制参数是反模式。我希望建造商:

  • 确保工作正常,不会抛出异常
  • 不要在引擎盖下做繁重的计算

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

多亏了move构造函数,您可以执行以下操作:

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));
    }
};
类对象{
std::唯一的\u ptr foo;
显式对象(std::unique_ptr&&foo_):foo(std::move(foo_)){
公众:
来自FooArg的静态对象(const FooArg&FooArg){
//在此处使用fooArg创建foo
std::unique_ptr foo=。。。
返回对象(std::move(foo));
}
};
直接从所需的参数初始化构造函数中的实例有什么错

class Object
{
    Foo foo;                         // or const Foo foo, disallowing assignment

public:

    explicit Object(FooCtorArgs const&fooArg,
                    const AdditionalData*data = nullptr)
      : foo(fooArg)                  // construct instance foo directly from args
    {
        foo.post_construction(data); // optional; doesn't work with const foo
    }

    static Object FromFooArg(FooCtorArgs const&fooArg,
                             const AdditionalData*data = nullptr)
    { 
        return Object{fooArg,data};  // copy avoided by return value optimization
    }
};

AFAICT,即使需要调整
foo
post-construction,也不需要复制/移动任何内容。

由于C++11,您可以使用移动语义。但这是一个复杂的话题;最好的答案是一本好书,比如Stroustrup。写得很好的问题+1.严格来说,你的第一个版本的公共电脑也很贵。您默认初始化
foo
(我假设所有初始化都很昂贵),然后创建另一个
foo
对象,并将其分配给默认构造的对象。@StoryTeller-Hmm,我不知道情况必然如此。我认为在第一个版本中,如果我执行
foo=foo(fooArg)
,则只调用该构造函数,不会发生复制。我的C++知识是从java中跳出来的。无论如何,我主要的应用关注点是复制而不是初始化(即使对于潜在的大型对象,例如空数组初始化,这也可能很便宜)。@Vossler-我建议在这里谨慎行事。C++对象模型与java非常不同。成员的初始化和复制不像Java中那样不相交。直接从
fooArg
初始化其
foo
的构造函数有什么问题?当然,这样的构造函数也可以被工厂仔细阅读。虽然这对我很有用,但这只适用于当
Foo
有一个直接来自
FooArg
(对吗?)的构造函数时的特殊情况。相反,如果在
fromoarg
中,我默认初始化
foo
,并使用
fooArg
中的一些计算(或一般情况下的其他参数)手动填充它,那么您将不得不返回到我的原始代码段。此外,这种解决方案类型的软件违反了我不让构造函数执行复杂初始化逻辑的动机(这取决于
FooArg
也遵守此约定)。这种担心是一种误导。在这种情况下,您可以在工厂或
对象的构造函数中填写
对象::foo
实例,请参见编辑。但是,一个设计良好的
类Foo
不需要这样的构造后初始化。@ÖTiib请阅读我的原始问题-无论是文本还是代码都表明我假设
Foo
有一个直接来自
FooArg
的构造函数。如果你认为原始问题的表述不好,那么你就有理由对它进行否决,但是你的意思是,我对这个答案的评论对“代码> FoO < /代码>实施了某种特别的约束是错误的。”您的
对象
只能从
FooArg
构造,并且具有
Foo
组件,这清楚地表明
Foo
也只能从
FooArg
构造。否则,信息确实会从一些未声明的依赖项横向流入。@ÖTiib
Foo
确实可以从
FooArg
构造,但不必定义直接构造函数。谁说我可以控制
Foo
?谢谢!我可能偏向于这些解决方案b/c,这或多或少模仿了我更熟悉的Java通过引用传递的风格。关于这一点有两个问题:1)一个更接近的Java克隆将使用