テンポラリオブジェクトに直接介入するには

解決


ムナ  2003-05-15 23:45:27  No: 51391

いつもお世話になっております
  
下記のような記述をした場合
 
MYCLASS operatir+(MYCLASS &a, MYCLASS &b){
    MYCLASS ret;
    ・・・・   // a + b を処理し ret に格納
    return ret
}
   
return ret のところで 
ret のコピー(テンポラリオブジェクト?)が作成され
( MYCLASS(MYCLASS &x) で定義されたコンストラクタが走ります)
コピーが返値として 返ります
  
ここで コピー を作成するのは無駄なので
いずれ 返値になるであろう テンポラリオブジェクト を先に生成し
a + b の結果を格納して 返してやる方法はないでしょうか
 
 
MYCLASS& operatir+(MYCLASS &a, MYCLASS &b){
    MYCLASS *ret = new MYCLASS();
    ・・・
    return *ret;
}
 
だと コピーは作成されませんが
どこかのタイミングで delete が必要になるんですよね〜
 
MYCLASS a, b, c;
a = b + c;
 
とかやったら どこを delete してよいものやら・・・


ムナ  2003-05-15 23:51:01  No: 51392

operator だね
つづり間違えてる・・・
はずかし


hu  2003-05-16 00:49:20  No: 51393

余分な部分もありますが、下記コードで下のように入れ替えを行った際の
"copy constructor"等の出力数を数えてみて下さい。
・operator +()の実装:(1)と(2)を入れ替える
・返り値の受けてのインスタンス生成方法:(3)と(4)を入れ替える

class A {
private:
  int num;
public:
  A(int n = 0) : num(n) { cout << "not copy constructor" << endl; }
  A(const A& a) : num(a.num) { cout << "copy constructor" << endl; }

  A& operator =(const A& r) {
    num = r.num;
    cout << "operator =" << endl;
    return *this;
  }
  int get() const { return num; }
};

A operator +(const A& op1, const A& op2) { return A(op1.get() + op2.get()); } // (1)
A operator +(const A& op1, const A& op2) {
  A result(op1.get() + op2.get());
  return result;
} // (2)

int main(int argc, char **argv) {
  A a1(5), a2(8);
  A a3(a1 + a2); // (3)
  A a3 = a1 + a2; // (4)
  cout << a3.get() << endl;
  a3 = a1;
  cout << a3.get() << endl;
}


hu  2003-05-16 01:01:16  No: 51394

書き忘れました。こちらは、
  OS:HP-UX,コンパイラ:aCC
で実験しましたが、それぞれの入れ替えで効果がありました。
コンパイラの実装依存の話かと思いますが、どのコンパイラも返り値最適化程度は
行っているのではないかと。


ムナ  2003-05-16 01:37:20  No: 51395

わたしの 環境は
Windows2000, VC6SP5 です

(1)-(3)
not copy constructor
not copy constructor
not copy constructor
13
operator =
5

(1)-(4)
not copy constructor
not copy constructor
not copy constructor
13
operator =
5

(2)-(3)
not copy constructor
not copy constructor
not copy constructor
copy constructor
13
operator =
5

(2)-(4)
not copy constructor
not copy constructor
not copy constructor
copy constructor
13
operator =
5

上記のような結果になりました

return MYCLASS();

のように 記述すると コピーを作成しないようですね

でも
return MYCLASS(a.member + b.member);

のような 簡単な + 演算なら この記述でいけるのですが
もっと複雑な(実は 多倍長演算のライブラリ作ろうと思って)場合
MYCLASS( の中に 記述しきれませんよね・・・

やはり ワーク変数 result をそのまま返値としたいです
いい方法ないでしょうか


YuO  2003-05-16 03:12:31  No: 51396

More Effective C++の第20項とか,
Efficient C++の第4章を参照してみて下さい。

RVOを利用できるか否かは,コンパイラに依存します。
基本的には「できたらもうけもの」程度の意識でいるのがよいと思います。


ムナ  2003-05-16 18:28:36  No: 51397

RVO(Return Value Optimization) ですか>ちょっと調べてみました
その中でも 今回やりたいことは
NRVO (Named Return Value Optimization)
と呼ばれるものみたいですね

VC++ のコンパイラでは RVO までしかサポートしていない模様でした

ま 最悪
MYCLASS(MYCLASS &a, MYCLASS &b, int flg)
のような コンストラクタを作成し
すべての 演算を コンストラクタ内で行う という手を いま思いつきました
これで コピーコンストラクタ は走らなくなりますが
記述が大変だ・・・

Efficient C++ って有名な 書籍みたいですね
3,500円か〜
近所のパソショップに置いてあったら一読してみようと思います

以上 ありがとうございました


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加