2

C++ で不変型 (クラス) を作成しようとしていますが、

すべてのメソッド「別名メンバー関数」がオブジェクトを変更せず、代わりに新しいインスタンスを返すようにしました。

私はたくさんの問題に出くわしていますが、それらはすべて C++ の参照型を中心に展開しています。

1 つの例は、参照によって同じクラス型のパラメーターを渡す場合です。

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   p_im = p_im.someOtherOp(); //error, p_im is const, can't modify it!
   ...
}

エラーは、参照によって値を渡すことによって発生します。代わりに、参照を値渡ししていた場合、上記のエラー行はエラーにはなりません!

Java/C# の例を考えてみましょう

class Imm
{
    ...
    Imm someOp( Imm p_im )
    {
        ....
        p_im = p_im.someOtherOp(); //ok, you're not modifying the 
                 //original object, just changing the local reference
        ....  
    }
    ....
}

C ++でこのようなことを行うにはどうすればよいですか? ポインターを使用できることはわかっていますが、メモリ管理全体が混乱します。オブジェクトへの参照を誰が所有しているかについて心配したくありません。

理想的には、クラスを Python の不変文字列のように設計したいと考えています。それらが不変であることを気付かずに、または知らずに使用でき、期待どおりに動作します。彼らはただ働きます。

編集

もちろん、値渡しまたは一時変数を使用することで回避できます (これは私が現在行っていることです)。私が尋ねているのは、「C ++で参照を値で渡す方法」です

私は答えがSTLの何かを中心に展開することを期待しています.私は現在smart_ptrファミリーのテンプレートを調べています.

アップデート

返信ありがとうございます。ポインタから逃れることはできません。(私の他の質問を参照してください。これは実際にはこの質問のフォローアップです)

4

7 に答える 7

4

Java と C# では、実際には参照を扱っているわけではなく、ハンドルやポインターに似ています。C++ での参照は、実際には元のオブジェクトの別の名前であり、元のオブジェクトへのポインターではありません (ただし、ポインターで実装される場合があります)。参照に値を代入すると、オブジェクト自体に代入されます。参照を初期化するために文字を使用できるという点で混乱がありますが=、これは代入ではなく初期化です。

 Imm im, im2, im3; 
 Imm &imr = im;  // initialize a reference to im
 imr = im2; // assign im2 to imr (changes the value of im as well)
 Imm *imp = &im; // initialize a pointer to the address of im
 imp = &im3; // assign the address of im3 to imp (im is unnaffected);
 (*imp) = im2; // assign im2 to imp (modifies im3 as well).

特に「値による参照」を渡したい場合は、基本的に用語の矛盾を求めています。参照は、定義上、参照によって渡されます。他の場所で指摘されているように、ポインターを値で渡すことも、そのままの値を渡すこともできます。本当に必要な場合は、クラス内の参照を保持し、それを値で渡すことができます。

 struct ImmRef
 {
     Imm &Ref;
     ImmRef(Imm &ref) : Ref(ref) {}
 };

また、参照に適用される const は、参照ではなく、参照されるオブジェクトを定数にすることにも注意してください。参照は常に const です。

于 2009-03-16T01:30:55.797 に答える
4

定義上、代入は一定の操作ではありませんか?

const 参照に何かを割り当てようとしているように見えますが、これは const 参照のアイデアを完全に無効にします。

参照ではなくポインターを探している可能性があると思います。

于 2009-03-16T00:50:09.157 に答える
3

C++ではそのようには機能しません。

オブジェクトへの参照を渡すときは、実際にはオブジェクトのメモリ内のアドレスを渡します。参照を他のオブジェクトに再配置することもできないため、C++の格言は「参照はオブジェクトです」。あなたはそれを修正するためにコピーを作成する必要があります。Javaはこれを舞台裏で行います。C ++、あなたはそれをコピーする必要があります。

于 2009-03-16T04:24:38.330 に答える
1

呼び出すメソッドを const にするのを忘れていませんか?

編集:したがって、constが修正されました。

多分あなたは次のようなことをするべきです

Imm & tmp = p_im.someOtherOp();

次に、tmp 変数に対してさらに操作を行います。

変数またはパラメーターを const & として設定した場合、それに割り当てることはできません。

于 2009-03-16T00:45:47.030 に答える
0

着信引数の新しいコピーを作成する必要があります。いくつかの同等の方法で必要なことを行うことができます: 1) 値渡しが可能です:

Imm Imm::someOp( Imm im ) const {
   im = im.someOtherOp();      // local im is a copy, original im not modified
   return im;                  // return by value (another copy)
}

または 2) 参照渡しして明示的にコピーを作成できます。

Imm Imm::someOp( const Imm & im ) const {
   Imm tmp = im.someOtherOp(); // local tmp is a copy
   return tmp;                 // return by value (another copy)
}

どちらの形式も同等です。

于 2009-03-16T00:58:49.433 に答える
0

一時的な有効期間について知るには、これを確認してください http://herbsutter.wordpress.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   //Imm& im = p_im.someOtherOp();       // will *not* work
   const Imm& im = p_im.someOtherOp();   // will work, but you get a const reference
   ...
}

ただし、boost::shared_ptr を使用できます

shared_ptr<Imm> Imm::someOtherOp() const
{
  shared_ptr<Imm> ret = new Imm;
  ...
  return ret;
}

shared_ptr<Imm> Imm::someOp(const share_ptr<Imm>& p_im) const
{
  shared_ptr<Imm> im = p_im->someOtherOp();
}
于 2009-03-16T05:20:56.870 に答える