2

このトピックをさらに使い果たしたいと思います。

次のようなものがあるとします。

class MyClass
{
public: 

MyClass(int N)
{ 
    data_ptr = new float[N];
};

float* dat_ptr;    

// ... clever operator definition here ...
};

だから私は簡単に書くことができるようにしたいと思います:

MyClass a(4);
MyClass b(4);
MyClass c(4);

// modify b.data_ptr and c.data_ptr ....
// Use "clever operator"
a = b + c;

オペレーターが実行する場所 a.data_ptr[i] = b.data_ptr[i] + c.data_ptr[i] for i=0:(N-1) ...

したがって、データの余分なコピーは作成されず、事前に割り当てられたバッファーを適切に使用しています。

これは可能ですか?もしそうなら、それがどのように行われるかについてのいくつかの洞察を私に提供してください.

ありがとう!

4

3 に答える 3

1

それは不可能; a が代入される前に、operator + (b, c) を呼び出した結果として一時オブジェクトが作成されます。この演算子は、作成されたインスタンスを返す必要があります。これは、に割り当てられる必要があります。作成されたインスタンスは常に b + c によって作成されます。

ただし、 += をメンバー演算子として定義して、次のように言うことができます。

b += c;

これにより、余分なコピーを作成せずに b の値が変更されます。

編集:私は再考しました:)

操作を遅延評価オブジェクトとして抽象化することで、間違いなくそれを行うことができます。

次に例を示します。

class MyClass; // fwd. declaration of your class

struct LazySum
{
    LazySum(const MyClass& a, const MyClass& b)
    : x(a), y(b) {}

    float operator[](int i) { return x[i] + y[i]; }

    const MyClass& x;
    const MyClass& y;
};

class MyClass
{
public: 
    MyClass(int N)
    { 
        data_ptr = new float[n = N];
    };

    int n;           // this shouldn't be public
    float* dat_ptr;  // nor this, but I went with your code

    // ... clever operator definition here ...
    MyClass& operator=(const LazySum& terms)
    {
        // ignore case when n != x.n or n != y.n
        // because not the point of the example
        // (and I'm lazy)

        // sum evaluation occurs here
        // with no new allocations
        for(int i = 0; i < n; ++i)
            data_ptr[i] = terms[i]; 
        return *this;
    }
};

LazySum operator=(const MyClass& x, const MyClass& y)
{
    return LazySum(x, y); // LazySum is a couple of references in size
}

void client_code_using_clever_op()
{
    MyClass a(4);
    MyClass b(4);
    MyClass c(4);

    // modify b.data_ptr and c.data_ptr ....
    // Use "clever operator"
    a = b + c; // actual sum performed when operator = is executed
}

アイデアは、項を保存し、項に対して後期評価を実行することです。

改善点:

  • LazySum の構築にファンクターを挿入して LazyOp にします (ファンクターは op が何であるかを決定します)。それに関して、MyClass に他の二項演算子を実装します。

  • MyClass で RAII を使用します。

  • 別の型 (例: some ) に遅延評価演算子を実装する必要がある場合はMyOtherClass、項およびファンクター型のテンプレートとして LazyOp を実装することを検討してください。

  • これは、追加の作業なしでは、より複雑な式をサポートしていません。

    MyClass a(4)、b(4)、c(4)、d(4);

    d = (a + b) + c; // エラー

    operator+(const LazySum&, const MyClass&);この例は、 ;が必要なため機能しません。

于 2013-05-29T09:30:46.913 に答える
1

C++11 のムーブ セマンティクスを使用すれば可能です。

class MyClass
{
public: 

    MyClass(int N)
    { 
        data_ptr = new float[N];
        n = N;
    }

    MyClass(MyClass && rhs)
    {
        data_ptr = rhs.data_ptr;
        n = rhs.n;

        rhs.data_ptr = nullptr;
    }

    // dtor, copy-ctor etc.

    int n;
    float * dat_ptr;    
};

MyClass operator + (const MyClass & left, const MyClass & right)
{
    MyClass result(left.n);

    // Implement addition
}

// Note: no error-checking

この方法で一時オブジェクト作成されますが、内部データ不必要にコピーされることはありません。

移動セマンティクスの詳細を参照してください。

于 2013-05-29T09:38:07.950 に答える