2

B既に定義されており、C++ コードのどこかで使用されている配列があるとします。Aここで、定義および初期化された別の配列があるとします。f変換する関数A(FFT など) を作成し、変換の結果を に割り当てたいB(もちろん、 の変換に続いて、AそのB値が変更されます)。私は構文を維持することによってそれをすべてやりたい

B=f(A);

つまり、 のアドレスをB引数としてに渡さないでくださいf。出来ますか:

  1. 一時的な作成なしで?
  2. 一時的なものを作成しますが、メモリリークはありませんか?

ありがとうございました。

編集:以下の回答で提供されるソリューションの概要

RiaD、James Kanze、Shahbaz、Razispio の回答に感謝します。

私が求めているのは、効率AB効果を得るために、配列クラスのオブジェクトであることが必要です。また、コピー コンストラクタを備えた配列クラスなどの「標準」実装では、次のような構文B=f(A);では一時変数の作成が必要になります。ただし、多くのコンパイラは余分なテンポラリを省略できるため、テンポラリは必ずしも制限ではないことに注意してください。これとは反対に、次のような構文f(A,B);は一時的なものを避けます。式テンプレートを使用したソリューションではB=f(A);、内部で を使用しながら構文を有効にf(A,B);し、一時変数の使用を無視できるようにします。効率的な代替ソリューションは、移動代入演算子を使用することです。例を参照してください

C++11 でセマンティクスと右辺値参照を移動する

詳細については、以下の回答をご覧ください。

4

4 に答える 4

3

それを使用する最も簡単な方法std::vectorまたはstd::array

例:

vector<int> f(const vector<int>& a) {
   return a;
}

b = f(a);

実際には、このクラスのいずれかを使用して保存する必要はありません。独自のクラスを使用できます。operator =

YourClass& operator = (const vector<int>&/* there will be returned value of f, it may be std::array, std::vector or your own class.*/ v) {
    //fill it here.
    return *this;
}

不必要なコピーを避けるために、移動コンストラクターを提供することもできます。

例えば

class Array {
    int* data;   
    YourClass& operator = (YourClass&& v) {
        swap(v.data, data);
    }
}

YourClass f(const YourClass& a) {
   //
}

Array a,b;
b = f(a);
于 2013-04-27T17:11:48.613 に答える
1

f(a)にカスタム タイプを使用する意思がある場合は、どちらも可能です (またはほぼ可能です) b。アイデアは、あなたがすでに持っているということですb。したがって、意味的に引数として に渡したいと思いますf。たとえば、代入演算子をオーバーロードできます。

まず、式の概念を定義します (ここでは抽象クラスとして表されていますが、実際には仮想ディスパッチを使用したくありません)。これは計算をカプセル化しEvaluate、結果を に返すことができますtarget

template<typename T>
class Expression
{
public:
    virtual void Evaluate(T& target) const = 0;
}

クラスから割り当てることができる配列クラスを定義しますExpression。式が割り当てられると、評価されます。

template<typename T>
class Array
{
   T* ptr;
public:
   template<typename Expression>
   const Array<T> operator =(Expression const & expression)
   {
      expression.Evaluate(ptr);
   }
}

fここで、式を返すように関数を定義します。これを評価すると、 が返されますf(a)

class MyExpression
{
    float* a;
public:
    MyExpression(float* a) : a(a) {}
    void Evaluate(float* target)
    {
        f(a, b);
    }
}

MyExpression<float> f(float* a) 
{ 
    return MyExpression(a);
}

次のように呼び出すことができます

Array b;
b = f(a);

これは (スタック上に) 一時的なものを作成しますが、インライン化される可能性があります。たとえば、次の呼び出しがあるとします。

b = f(a);

これはと同等です

b.operator = (f (a));

への呼び出しをインライン化するとoperator =

(f(a)).Evaluate(b);

fへの呼び出しをインライン化することもできます。

(MyExpression(f)).Evaluate(b);

これで、コンパイラは、これが実行とまったく同じであることに気付くことができます

f(a, b);

そしてすぐにそれを行います。したがって、一時的な を作成する必要はありませんがMyExpression、そもそもそのコストは無視できます (これは のスタック割り当てですsizeof(Array)) 。

このタイプの戦略は、たとえば一時的なものを避けるために行列ライブラリ固有値によって使用されることに注意してください。

于 2013-04-27T17:23:50.007 に答える
1

まず、配列の意味によって異なります。通常の C++ の意味 ( std::vector) では、メモリ リークの問題は発生しません。通常の C の意味 ( T[]) ではB = f( A )、違法です。std::vector独自の配列型を定義すると、この点で多かれ少なかれ同様に動作するはずです。

追加の一時変数に関して:f引数を渡すためのコピーがないように、その引数を const 参照として使用する必要があります。戻り値に関しては、正式にはコピーがありますが、コンパイラはそれを無視することが許可されており、ほとんどの場合、少なくとも時々はそうしています。代入ステートメントでは、配列の実際のデータはおそらく代入自体にコピーされます。

C++11 では、移動コンストラクターと移動代入演算子を提供でき、(おそらく) コピーの可能性をさらに減らすことができます。

于 2013-04-27T17:36:30.407 に答える