C ++でファクトリメソッドパターンを正しく実装する方法


329

簡単に聞こえますが、正直に言うとどうすればいいのかわからないので、C ++には長い間不快に感じていたものが1つあります。

C ++でFactoryメソッドを正しく実装するにはどうすればよいですか?

目標:許容できない結果やパフォーマンスへの影響なしに、クライアントがオブジェクトのコンストラクタの代わりにファクトリメソッドを使用してオブジェクトをインスタンス化できるようにすること。

「ファクトリー・メソッド・パターン」とは、オブジェクト内の静的なファクトリー・メソッドまたは別のクラスで定義されたメソッド、またはグローバル関数の両方を意味します。一般的には、「クラスXのインスタンス化の通常の方法をコンストラクター以外の場所にリダイレクトするという概念」です。

私が考えたいくつかの可能な答えをざっと見てみましょう。


0)工場を作らず、コンストラクタを作る。

これは良さそうですが(実際、多くの場合は最善の解決策です)、一般的な解決策ではありません。まず、オブジェクトの構築が別のクラスへの抽出を正当化するのに十分複雑なタスクである場合があります。しかし、その事実はさておき、コンストラクターだけを使用する単純なオブジェクトの場合でさえ、多くの場合そうしません。

私が知っている最も簡単な例は、2-D Vectorクラスです。とてもシンプルですが、トリッキーです。デカルト座標と極座標の両方から構築できるようにしたいと考えています。明らかに、私はできません:

struct Vec2 {
    Vec2(float x, float y);
    Vec2(float angle, float magnitude); // not a valid overload!
    // ...
};

私の自然な考え方は次のとおりです。

struct Vec2 {
    static Vec2 fromLinear(float x, float y);
    static Vec2 fromPolar(float angle, float magnitude);
    // ...
};

これは、コンストラクターの代わりに、静的ファクトリーメソッドの使用につながります...これは、本質的に、何らかの方法でファクトリーパターンを実装していることを意味します(「クラスが独自のファクトリーになる」)。これは見栄えがよく(この特定のケースに適しています)、場合によっては失敗します。これについては、ポイント2で説明します。

別のケース:一部のAPIの2つの不透明なtypedef(無関係なドメインのGUID、またはGUIDとビットフィールドなど)でオーバーロードしようとすると、意味的に完全に異なるタイプ(つまり、理論的には有効なオーバーロード)ですが、実際には同じこと-unsigned intやvoidポインタなど。


1)Javaの方法

動的に割り当てられたオブジェクトしかないため、Javaは単純です。工場を作ることは次のように簡単です:

class FooFactory {
    public Foo createFooInSomeWay() {
        // can be a static method as well,
        //  if we don't need the factory to provide its own object semantics
        //  and just serve as a group of methods
        return new Foo(some, args);
    }
}

C ++では、これは次のように変換されます。

class FooFactory {
public:
    Foo* createFooInSomeWay() {
        return new Foo(some, args);
    }
};

涼しい?しばしば、確かに。ただし、これにより、ユーザーは動的割り当てのみを使用する必要があります。静的割り当てはC ++を複雑にするだけでなく、強力にすることもよくあります。また、動的割り当てを許可しないいくつかのターゲット(キーワード:埋め込み)が存在すると思います。そして、それはそれらのプラットフォームのユーザーがクリーンなOOPを書きたがっていることを意味するものではありません。

とにかく、哲学は別として:一般的なケースでは、工場のユーザーに動的割り当てを強制することを強制したくありません。


2)値渡し

さて、動的割り当てが必要な場合は、1)が優れていることを理解しています。その上に静的割り当てを追加しないのはなぜですか?

class FooFactory {
public:
    Foo* createFooInSomeWay() {
        return new Foo(some, args);
    }
    Foo createFooInSomeWay() {
        return Foo(some, args);
    }
};

何?戻り値の型でオーバーロードできませんか?ああ、もちろんできません。それを反映するようにメソッド名を変更しましょう。そして、はい、私はメソッド名を変更する必要性をどれだけ嫌うかを強調するために、上記の無効なコードの例を書きました。このコードのすべてのユーザーは、実装と仕様の違いを覚えておく必要があります。

class FooFactory {
public:
    Foo* createDynamicFooInSomeWay() {
        return new Foo(some, args);
    }
    Foo createFooObjectInSomeWay() {
        return Foo(some, args);
    }
};

わかった…そこにある。メソッド名を変更する必要があるため、醜いです。同じコードを2回書く必要があるため、これは不完全です。しかし、一度完了すると、機能します。正しい?

まあ、通常。しかし、時々それはしません。Fooを作成するとき、実際にコンパイラーに依存して戻り値の最適化を行っています。C++標準は、コンパイラーベンダーがオブジェクトをインプレースで作成するタイミングと、オブジェクトを返すときにコピーするタイミングを指定しないように十分に慈善的であるためです。 C ++の値による一時オブジェクト。したがって、Fooのコピーにコストがかかる場合、このアプローチは危険です。

また、Fooがまったくコピーできない場合はどうなりますか?まあ、そう。(コピーの省略が保証されたC ++ 17では、コピー不可であっても上記のコードでは問題ありません

結論:オブジェクトを返すことでファクトリーを作成することは、確かにいくつかのケース(前述の2Dベクトルなど)の解決策ですが、それでもコンストラクターの一般的な置き換えではありません。


3)二相構造

おそらく誰かが思いつくもう1つのことは、オブジェクトの割り当てとその初期化の問題を分離することです。これは通常、次のようなコードになります。

class Foo {
public:
    Foo() {
        // empty or almost empty
    }
    // ...
};

class FooFactory {
public:
    void createFooInSomeWay(Foo& foo, some, args);
};

void clientCode() {
    Foo staticFoo;
    auto_ptr<Foo> dynamicFoo = new Foo();
    FooFactory factory;
    factory.createFooInSomeWay(&staticFoo);
    factory.createFooInSomeWay(&dynamicFoo.get());
    // ...
}

それは魅力のように機能すると考えるかもしれません。コードで支払う唯一の価格...

全部書いて最後に残したので嫌いなのも。:) なぜ?

まず…二相構造のコンセプトが嫌いで、使うと罪悪感を覚えます。「存在する場合は有効な状態である」というアサーションを使用してオブジェクトを設計すると、コードがより安全になり、エラーが発生しにくくなります。それが好き。

その慣習を落とし、私のオブジェクトのデザインを変更しなければならないのは、それをファクトリーにするためだけです。

上記は多くの人を納得させるものではないことを知っているので、もっとしっかりした議論をしましょう。2フェーズ構成を使用すると、次のことはできません。

  • constメンバー変数の初期化または参照、
  • 基本クラスコンストラクターとメンバーオブジェクトコンストラクターに引数を渡します。

そして、おそらく今は考えられないいくつかの欠点があるかもしれませんし、上記の箇条書きがすでに私を納得させているので、特に義務付けられているとさえ感じていません。

したがって、ファクトリを実装するための優れた一般的なソリューションにさえ近づきません。


結論:

次のようなオブジェクトのインスタンス化の方法が必要です。

  • 割り当てに関係なく、均一なインスタンス化を可能にし、
  • 構築メソッドに異なる意味のある名前を付けます(したがって、引数によるオーバーロードに依存しません)。
  • 特にクライアント側で、重大なパフォーマンスヒット、およびできれば、重要なコードブロートヒットを導入しない
  • 次のように一般的である:どのクラスにも導入できる。

私が述べた方法はそれらの要件を満たしていないことを私は証明したと信じています。

ヒントはありますか?私に解決策を提供してください、この言語では私がそのような些細な概念を適切に実装することができないとは思わないでください。


7
@Zac、タイトルは非常に似ていますが、実際の質問は私見とは異なります。
ペーテルTörök

2
良い複製ですが、この質問のテキスト自体は貴重です。
dmckee ---元モデレーターの子猫

7
これを尋ねてから2年後、私は追加するいくつかのポイントがあります:1)この質問はいくつかの設計パターンに関連しています([abstract]ファクトリー、ビルダー、あなたが名前を付けます、私は彼らの分類法を掘り下げるのは好きではありません)。2)ここで議論されている実際の問題は、「オブジェクトのストレージ割り当てをオブジェクトの構築から明確に分離する方法」です。
コス

1
@Dennis:そうでない場合のみdelete。これらの種類のメソッドは、呼び出し元がポインターの所有権を取得することが「ドキュメント化」されている限り(ソースコードはドキュメント;-)完全に問題ありません(読み取り:必要に応じて削除する責任があります)。
Boris Dalstein 2013

1
@Boris @Dennis unique_ptr<T>では、の代わりにを返すことで、それを非常に明示的にすることもできますT*
Kos

回答:


107

まず、オブジェクトの構築が別のクラスへの抽出を正当化するのに十分なほど複雑なタスクである場合があります。

この点は間違っていると思います。複雑さはそれほど重要ではありません。関連性は何をするかです。オブジェクトが1つのステップで(ビルダーパターンとは異なり)構築できる場合は、コンストラクターが適切な場所です。ジョブを実行するために本当に別のクラスが必要な場合は、とにかくコンストラクターから使用されるヘルパークラスである必要があります。

Vec2(float x, float y);
Vec2(float angle, float magnitude); // not a valid overload!

これには簡単な回避策があります:

struct Cartesian {
  inline Cartesian(float x, float y): x(x), y(y) {}
  float x, y;
};
struct Polar {
  inline Polar(float angle, float magnitude): angle(angle), magnitude(magnitude) {}
  float angle, magnitude;
};
Vec2(const Cartesian &cartesian);
Vec2(const Polar &polar);

唯一の欠点は、少し冗長に見えることです。

Vec2 v2(Vec2::Cartesian(3.0f, 4.0f));

ただし、良い点は、使用している座標の種類をすぐに確認できることと、コピーを気にする必要がないことです。コピーが必要で、それが高価な場合(もちろんプロファイリングで証明されています)、次のようなものを使用できます Qtの共有クラスのしますして、コピーのオーバーヘッドを回避するします。

割り当てタイプについては、ファクトリパターンを使用する主な理由は通常、ポリモーフィズムです。コンストラクタを仮想化することはできません。仮想化できても、あまり意味がありません。静的割り当てまたはスタック割り当てを使用する場合、コンパイラは正確なサイズを知る必要があるため、オブジェクトを多態的に作成することはできません。したがって、ポインタと参照でのみ機能します。ファクトリから参照を返すことも機能しません。オブジェクトは技術的に参照によって削除できますが、混乱を招く可能性があり、バグが発生しやすくなる可能性があります。C++参照変数を返す方法は悪いですか?例えば。したがって、残っているのはポインターだけであり、これにはスマートポインターも含まれます。言い換えると、ファクトリはダイナミックアロケーションで使用する場合に最も有用であるため、次のようなことができます。

class Abstract {
  public:
    virtual void do() = 0;
};

class Factory {
  public:
    Abstract *create();
};

Factory f;
Abstract *a = f.create();
a->do();

他の場合では、工場はあなたが言及したオーバーロードのような小さな問題を解決するのに役立ちます。統一して使えればいいのですが、多分不可能ではないでしょうか。


21
デカルトおよびポーラー構造体の場合は+1。一般に、(一般的なVec構造体とは対照的に)対象となるデータを直接表すクラスと構造体を作成するのが最善です。あなたのファクトリーも良い例ですが、あなたの例はポインター 'a'の所有者を示していません。ファクトリ「f」がそれを所有している場合、「f」がスコープを離れると破棄される可能性がありますが、「f」がそれを所有していない場合は、開発者がそのメモリを解放することを忘れないでください。発生する。
David Peterson

1
もちろんオブジェクトは参照により削除できます!stackoverflow.com/a/752699/404734を参照してください。もちろん、コピーによって戻り値を割り当てる可能性があるという問題があるため、参照によって動的メモリを返すのが賢明かどうかという疑問が生じます(呼び出し元はもちろん何かを行うこともできます) int a = * returnsAPoninterToInt()のように、参照のように動的にオールコートされたメモリが返された場合、同じ問題に直面しますが、ポインタバージョンでは、ユーザーは明示的に参照するのを忘れるのではなく、明示的に逆参照する必要があります) 。
Kaiserludi 2013

1
@Kaiserludi、いいポイント。私はそのことを考えていませんでしたが、それでも物事を行うには「邪悪な」方法です。それを反映するために私の答えを編集しました。
セルゲイタシェノフ2013

不変であるさまざまな非ポリモーフィッククラスの作成についてはどうですか?ファクトリパターンはC ++での使用に適していますか?
daaxix 2014年

@daaxix、非ポリモーフィッククラスのインスタンスを作成するためにファクトリが必要なのはなぜですか?不変性がこれとどう関係しているのかわかりません。
Sergei Tachenov 2014年

49

単純なファクトリの例:

// Factory returns object and ownership
// Caller responsible for deletion.
#include <memory>
class FactoryReleaseOwnership{
  public:
    std::unique_ptr<Foo> createFooInSomeWay(){
      return std::unique_ptr<Foo>(new Foo(some, args));
    }
};

// Factory retains object ownership
// Thus returning a reference.
#include <boost/ptr_container/ptr_vector.hpp>
class FactoryRetainOwnership{
  boost::ptr_vector<Foo>  myFoo;
  public:
    Foo& createFooInSomeWay(){
      // Must take care that factory last longer than all references.
      // Could make myFoo static so it last as long as the application.
      myFoo.push_back(new Foo(some, args));
      return myFoo.back();
    }
};

2
@LokiAstariスマートポインターの使用がメモリの制御を失う最も簡単な方法だからです。他の言語と比較してどのC / C ++言語が最も優れているかを制御し、それらの言語から最大の利点を得ます。スマートポインターが他のマネージ言語と同様のメモリオーバーヘッドを生成するという事実については触れません。自動メモリ管理の利便性が必要な場合は、JavaまたはC#でプログラミングを開始しますが、その混乱をC / C ++に組み込まないでください。
luke1985

45
@ lukasz1985 unique_ptrその例では、パフォーマンスのオーバーヘッドはありません。メモリーを含むリソースの管理は、パフォーマンスを犠牲にすることなく、また決定論的に、制御を失うことなく実行できるため、他の言語よりもC ++の最大の利点の1つですが、まったく逆です。スマートポインタによるメモリ管理のように、C ++が暗黙的に行うことを嫌う人もいますが、必要なものがすべて明示的に明示的になるようにする場合は、Cを使用します。トレードオフは桁違いに少ない問題です。あなたが良い推薦に反対票を投じることは不公平だと思います。
TheCppZoo

1
@EdMaster:彼は明らかにトローリングしていたので、以前は応答しませんでした。トロルに餌を与えないでください。
マーティンヨーク

17
@LokiAstari彼はトロールかもしれないが、彼が言うことは人々を混乱させるかもしれない
TheCppZoo

1
@yau:はい。しかし:boost::ptr_vector<>作業をサブクラスに委任するのではなく、ポインターを所有していると理解できるため、少し効率的です。ただし、その主な利点はboost::ptr_vector<>、メンバーを参照(ポインターではなく)で公開することです。そのため、標準ライブラリのアルゴリズムを使用するのは非常に簡単です。
マーティンヨーク

41

ファクトリをまったく使用せず、代わりに型システムをうまく利用することを考えましたか?このようなことを行う2つの異なるアプローチを考えることができます。

オプション1:

struct linear {
    linear(float x, float y) : x_(x), y_(y){}
    float x_;
    float y_;
};

struct polar {
    polar(float angle, float magnitude) : angle_(angle),  magnitude_(magnitude) {}
    float angle_;
    float magnitude_;
};


struct Vec2 {
    explicit Vec2(const linear &l) { /* ... */ }
    explicit Vec2(const polar &p) { /* ... */ }
};

次のようなものを書くことができます:

Vec2 v(linear(1.0, 2.0));

オプション2:

STLがイテレータなどで行うように「タグ」を使用できます。例えば:

struct linear_coord_tag linear_coord {}; // declare type and a global
struct polar_coord_tag polar_coord {};

struct Vec2 {
    Vec2(float x, float y, const linear_coord_tag &) { /* ... */ }
    Vec2(float angle, float magnitude, const polar_coord_tag &) { /* ... */ }
};

この2番目のアプローチでは、次のようなコードを記述できます。

Vec2 v(1.0, 2.0, linear_coord);

これはまた、各コンストラクターに固有のプロトタイプを使用できるようにする一方で、見栄えがよく、優れています。


29

あなたは非常に良い解決策を読むことができます:http : //www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus

最善の解決策は「コメントとディスカッション」です。「静的なCreateメソッドは不要」を参照してください。

この考えから、私は工場を作りました。Qtを使用していますが、同等の標準のQMapとQStringを変更できます。

#ifndef FACTORY_H
#define FACTORY_H

#include <QMap>
#include <QString>

template <typename T>
class Factory
{
public:
    template <typename TDerived>
    void registerType(QString name)
    {
        static_assert(std::is_base_of<T, TDerived>::value, "Factory::registerType doesn't accept this type because doesn't derive from base class");
        _createFuncs[name] = &createFunc<TDerived>;
    }

    T* create(QString name) {
        typename QMap<QString,PCreateFunc>::const_iterator it = _createFuncs.find(name);
        if (it != _createFuncs.end()) {
            return it.value()();
        }
        return nullptr;
    }

private:
    template <typename TDerived>
    static T* createFunc()
    {
        return new TDerived();
    }

    typedef T* (*PCreateFunc)();
    QMap<QString,PCreateFunc> _createFuncs;
};

#endif // FACTORY_H

使用例:

Factory<BaseClass> f;
f.registerType<Descendant1>("Descendant1");
f.registerType<Descendant2>("Descendant2");
Descendant1* d1 = static_cast<Descendant1*>(f.create("Descendant1"));
Descendant2* d2 = static_cast<Descendant2*>(f.create("Descendant2"));
BaseClass *b1 = f.create("Descendant1");
BaseClass *b2 = f.create("Descendant2");

17

私はほとんど受け入れられた回答に同意しますが、既存の回答ではカバーされていないC ++ 11オプションがあります。

  • ファクトリメソッドの結果を値で返す
  • 安価な移動コンストラクタを提供します。

例:

struct sandwich {
  // Factory methods.
  static sandwich ham();
  static sandwich spam();
  // Move constructor.
  sandwich(sandwich &&);
  // etc.
};

次に、スタック上にオブジェクトを構築できます。

sandwich mine{sandwich::ham()};

他のもののサブオブジェクトとして:

auto lunch = std::make_pair(sandwich::spam(), apple{});

または動的に割り当てられます:

auto ptr = std::make_shared<sandwich>(sandwich::ham());

これはいつ使用できますか?

パブリックコンストラクターで、事前の計算なしにすべてのクラスメンバーに意味のあるイニシャライザーを与えることができない場合、そのコンストラクターを静的メソッドに変換する可能性があります。静的メソッドは、予備的な計算を実行し、メンバーごとの初期化のみを行うプライベートコンストラクターを介して値の結果を返します。

私は、 ' かもしれない ' と言います。なぜなら、それは、どのアプローチが不必要に非効率的でなく、最も明確なコードを与えるかに依存するからです。


1
OpenGLリソースをラップするときに、これを広範囲に使用しました。削除されたコピーコンストラクターとコピーの割り当ては、移動セマンティクスの使用を強制します。次に、各タイプのリソースを作成するための一連の静的ファクトリメソッドを作成しました。これは、渡された列挙型に応じて冗長な関数パラメーターの束を持つことが多いOpenGLの列挙型ランタイムディスパッチよりもはるかに読みやすかったです。これは非常に便利なパターンですが、この答えはそれほど高くありません。
フィブルズ、

11

LokiにはFactoryメソッドAbstract Factoryの両方があります。両方とも、Andei AlexandrescuによるModern C ++ Designに(広範囲に)文書化されています。ファクトリメソッドはおそらく少し後の方に近いと思われますが、それでも少し異なります(少なくともメモリが機能する場合、ファクトリがその型のオブジェクトを作成する前に型を登録する必要があります)。


1
古くなったとしても(私は論争です)、それでも完全に保守可能です。新しいC ++ 14プロジェクトで、MC ++ Dに基づくファクトリーを使用して、すばらしい効果を得ています。さらに、ファクトリーとシングルトンのパターンはおそらく最も古いものではありません。以下のようなロキの作品ながらFunctionにして型操作を交換することができるstd::function<type_traits>ラムダ、スレッドは、右辺値参照文献は、いくつかのマイナーな微調整を必要とするかもしれない意味を持っている間、彼はそれらを記述のように、工場のシングルトンのための標準的な交換はありません。
金属

5

質問が広すぎると思うので、すべての質問に答えようとはしていません。ほんのいくつかのメモ:

オブジェクトの構築が別のクラスへの抽出を正当化するのに十分複雑なタスクである場合があります。

そのクラスは実際にはファクトリーではなくビルダーです。

一般的なケースでは、動的割り当てに工場のユーザーを拘束することを強制したくありません。

次に、ファクトリーでスマートポインターにカプセル化できます。私はこの方法であなたがあなたのケーキを持って、それを食べることもできると信じています。

これにより、値による戻りに​​関連する問題も解消されます。

結論:オブジェクトを返すことでファクトリーを作成することは、確かにいくつかのケース(前述の2Dベクトルなど)の解決策ですが、それでもコンストラクターの一般的な置き換えではありません。

確かに。すべてのデザインパターンには、(言語固有の)制約と欠点があります。自分のためではなく、問題の解決に役立つ場合にのみ使用することをお勧めします。

「完全な」ファクトリー実装の後である場合は、まあ、頑張ってください。


答えてくれてありがとう!しかし、スマートポインターを使用すると、動的割り当ての制限がどのように解除されるかを説明できますか?私はこの部分を完全には理解できませんでした。
Kos

@Kos、スマートポインターを使用すると、実際のオブジェクトの割り当て/割り当て解除をユーザーから隠すことができます。カプセル化されたスマートポインターのみが表示され、外部への静的な割り当てオブジェクトのように動作します。
ペーテルTörök

@Kos、厳密な意味ではありません、AFAIR。ラップするオブジェクトを渡します。これはおそらく、ある時点で動的に割り当てたものです。次に、スマートポインターがその所有権を取得し、不要になったときに適切に破棄されるようにします(その時間は、スマートポインターの種類によって異なります)。
ペーテルTörök

3

これは私のc ++ 11スタイルのソリューションです。パラメータ 'base'は、すべてのサブクラスの基本クラス用です。作成者はstd :: functionオブジェクトであり、サブクラスインスタンスを作成します。これは、サブクラスの静的メンバー関数 'create(some args)'へのバインディングである可能性があります。これはおそらく完璧ではありませんが、私にとってはうまくいきます。そして、それはちょっと「一般的な」ソリューションです。

template <class base, class... params> class factory {
public:
  factory() {}
  factory(const factory &) = delete;
  factory &operator=(const factory &) = delete;

  auto create(const std::string name, params... args) {
    auto key = your_hash_func(name.c_str(), name.size());
    return std::move(create(key, args...));
  }

  auto create(key_t key, params... args) {
    std::unique_ptr<base> obj{creators_[key](args...)};
    return obj;
  }

  void register_creator(const std::string name,
                        std::function<base *(params...)> &&creator) {
    auto key = your_hash_func(name.c_str(), name.size());
    creators_[key] = std::move(creator);
  }

protected:
  std::unordered_map<key_t, std::function<base *(params...)>> creators_;
};

使用例。

class base {
public:
  base(int val) : val_(val) {}

  virtual ~base() { std::cout << "base destroyed\n"; }

protected:
  int val_ = 0;
};

class foo : public base {
public:
  foo(int val) : base(val) { std::cout << "foo " << val << " \n"; }

  static foo *create(int val) { return new foo(val); }

  virtual ~foo() { std::cout << "foo destroyed\n"; }
};

class bar : public base {
public:
  bar(int val) : base(val) { std::cout << "bar " << val << "\n"; }

  static bar *create(int val) { return new bar(val); }

  virtual ~bar() { std::cout << "bar destroyed\n"; }
};

int main() {
  common::factory<base, int> factory;

  auto foo_creator = std::bind(&foo::create, std::placeholders::_1);
  auto bar_creator = std::bind(&bar::create, std::placeholders::_1);

  factory.register_creator("foo", foo_creator);
  factory.register_creator("bar", bar_creator);

  {
    auto foo_obj = std::move(factory.create("foo", 80));
    foo_obj.reset();
  }

  {
    auto bar_obj = std::move(factory.create("bar", 90));
    bar_obj.reset();
  }
}

私によく見えます。どのようにして静的登録を実装しますか(おそらくマクロマジック)。基本クラスがオブジェクトのサービスクラスであると想像してみてください。派生クラスは、これらのオブジェクトに特別な種類のサービスを提供します。また、さまざまな種類のサービスごとに、baseから派生したクラスを追加して、さまざまな種類のサービスを徐々に追加したいとします。
St0fF

2

工場パターン

class Point
{
public:
  static Point Cartesian(double x, double y);
private:
};

コンパイラが戻り値の最適化をサポートしていない場合は、それを取り除き、おそらくあまり最適化が含まれていません...


これは本当にファクトリーパターンの実装と考えることができますか?
Dennis

1
@デニス:退化したケースとして、私はそう思います。の問題Factoryは、それがかなり一般的であり、多くの範囲をカバーしていることです。たとえば、ファクトリは引数(環境/セットアップに応じて)を追加したり、キャッシュ(Flyweight / Poolsに関連する)を提供したりできますが、これらのケースは特定の状況でのみ意味があります。
Matthieu M. 2013

コンパイラを変更するだけで、音を立てるのと同じくらい簡単です:)
rozina

@rozina::) Linuxでうまく動作します(gcc / clangは非常に互換性があります)。私はWindowsがまだ比較的閉鎖されていることを認めますが、64ビットプラットフォームで改善されるはずです(覚えていれば、特許は少なくなります)。
Matthieu M.

そして、あなたはいくつかの劣ったコンパイラで全埋め込み世界を持っています.. :)私は戻り値の最適化を持たないようなもので作業しています。それがあったらいいのに。残念ながら現時点では、これを切り替えることはできません。うまくいけば、将来的にそれが更新されるか、私たちは他のものに切り替えるでしょう:)
rozina

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.