9

私は次のようなことをすることを理解しています:

auto&& x = Matrix1() + Matrix2() + Matrix3();
std::cout << x(2,3) << std::endl;

行列演算で式テンプレート ( などboost::ublas) を使用すると、サイレント ランタイム エラーが発生します。

コンパイラが実行時に期限切れの一時変数を使用する可能性があるコードをコンパイルしないように式テンプレートを設計する方法はありますか?

(この問題を回避しようとして失敗しました。その試みはこちらです)

4

2 に答える 2

7

コンパイラが実行時に期限切れの一時変数を使用する可能性があるコードをコンパイルしないように式テンプレートを設計する方法はありますか?

いいえ。これは実際には C++11 の最終的な標準化の前に認識されていましたが、委員会に通知されたかどうかはわかりません。修正が簡単だったというわけではありません。最も単純なことは、autoそれを推測しようとすると単にエラーになる型のフラグだと思いますが、それも推測できるため複雑でdecltypeあり、テンプレート引数の推測も同様です。そして、これら 3 つすべてが同じ方法で定義されていますが、おそらく後者が失敗することは望ましくありません。

ライブラリを適切に文書化して、誰もそのようにキャプチャしようとしないことを願っています。

于 2012-03-02T05:53:36.433 に答える
2

私が理解しているように、あなたの問題の根本は、式テンプレートの一時的なものが別の一時的なものへの参照/ポインターを持っている可能性があることです。また、 auto&& を使用することで、式テンプレート一時自体の寿命を延ばすだけで、それが参照する一時変数の寿命は延ばしません。そうですか?

たとえば、これはあなたの場合ですか?

#include <iostream>
#include <deque>
#include <algorithm>
#include <utility>
#include <memory>
using namespace std;

deque<bool> pool;

class ExpressionTemp;
class Scalar
{
    bool *alive;

    friend class ExpressionTemp;

    Scalar(const Scalar&);
    Scalar &operator=(const Scalar&);
    Scalar &operator=(Scalar&&);
public:
    Scalar()
    {
        pool.push_back(true);
        alive=&pool.back();
    }
    Scalar(Scalar &&rhs)
        : alive(0)
    {
        swap(alive,rhs.alive);
    }
    ~Scalar()
    {
        if(alive)
            (*alive)=false;
    }
};
class ExpressionTemp
{
    bool *operand_alive;
public:
    ExpressionTemp(const Scalar &s)
        : operand_alive(s.alive)
    {
    }
    void do_job()
    {
      if(*operand_alive)
          cout << "captured operand is alive" << endl;
      else
          cout << "captured operand is DEAD!" << endl;
    }
};

ExpressionTemp expression(const Scalar &s)
{
    return {s};
}
int main()
{
    {
        expression(Scalar()).do_job(); // OK
    }
    {
        Scalar lv;
        auto &&rvref=expression(lv);
        rvref.do_job(); // OK, lv is still alive
    }
    {
        auto &&rvref=expression(Scalar());
        rvref.do_job(); // referencing to dead temporary
    }
    return 0;
}

はいの場合、考えられる解決策の 1 つは、一時変数から移動されたリソースを保持する特別な種類の式テンプレート一時変数を作成することです。

たとえば、このアプローチを確認してください (再度バグ ケースを取得するには、BUG_CASE マクロを定義できます)。

//#define BUG_CASE

#include <iostream>
#include <deque>
#include <algorithm>
#include <utility>
#include <memory>
using namespace std;

deque<bool> pool;

class ExpressionTemp;
class Scalar
{
    bool *alive;

    friend class ExpressionTemp;

    Scalar(const Scalar&);
    Scalar &operator=(const Scalar&);
    Scalar &operator=(Scalar&&);
public:
    Scalar()
    {
        pool.push_back(true);
        alive=&pool.back();
    }
    Scalar(Scalar &&rhs)
        : alive(0)
    {
        swap(alive,rhs.alive);
    }
    ~Scalar()
    {
        if(alive)
            (*alive)=false;
    }
};
class ExpressionTemp
{
#ifndef BUG_CASE
    unique_ptr<Scalar> resource; // can be in separate type
#endif
    bool *operand_alive;
public:
    ExpressionTemp(const Scalar &s)
        : operand_alive(s.alive)
    {
    }
#ifndef BUG_CASE
    ExpressionTemp(Scalar &&s)
        : resource(new Scalar(move(s))), operand_alive(resource->alive)
    {
    }
#endif
    void do_job()
    {
      if(*operand_alive)
          cout << "captured operand is alive" << endl;
      else
          cout << "captured operand is DEAD!" << endl;
    }
};

template<typename T>
ExpressionTemp expression(T &&s)
{
    return {forward<T>(s)};
}
int main()
{
    {
        expression(Scalar()).do_job(); // OK, Scalar is moved to temporary
    }
    {
        Scalar lv;
        auto &&rvref=expression(lv);
        rvref.do_job(); // OK, lv is still alive
    }
    {
        auto &&rvref=expression(Scalar());
        rvref.do_job(); // OK, Scalar is moved into rvref
    }
    return 0;
}

演算子/関数のオーバーロードは、T&&/const T& 引数に応じて、異なる型を返す場合があります。

#include <iostream>
#include <ostream>
using namespace std;

int test(int&&)
{
    return 1;
}
double test(const int&)
{
    return 2.5;
};

int main()
{
    int t;
    cout << test(t) << endl;
    cout << test(0) << endl;
    return 0;
}

そのため、一時的な式テンプレートに一時的なリソースが移動されていない場合、そのサイズは影響を受けません。

于 2012-10-21T14:14:30.553 に答える