Hatena::ブログ(Diary)

みことメモ

2011-02-15

メンバ変数の参照返しについて

メンバ変数の参照返しについての記事にコメントをいただいたのでEffectiveC++を見直してみたけれど、ローカル変数の参照を返すべきではない、というようなことしか書いていなかった。

class Foo
{
public:
    void fuga();
};

class Hoge
{
public:
     const Foo& foo(){return foo_;}
private:
     Foo foo_;
};

において参照を返す場合のデメリットというのを一応考えてみた。
const参照なので、メンバのfooをコピーせずに、fugaを呼び出すと

(hoge.foo()).fuga();//コンパイルエラー

当然constじゃないメンバ関数を呼びだそうとすればコンパイルエラーになってしまう。デメリットとしては一時オブジェクトとして受け取った変数から更にconstじゃないメンバ関数/変数を呼び出せないということではないだろうか。

ただ、これは一時オブジェクトの寿命問題とともに

...
    {//寿命設定用のスコープ。
           Foo tmp = hoge.foo();
           tmp.fuga();
    }
...

のように書けばいい話で、それほどデメリットのようには感じ無い(普段constなメンバしか呼び出さない場合。必要な時にコピーすれば良いだけ)。

というわけで、今のところconst参照を返したほうが便利そうな気がする。さてはて・・・やっぱりメンバ変数の参照返しのデメリットってなんなのだろうか?ううむ.....

>>追記
コメントにて指摘していただいたので修正します。
メンバ関数

const Foo& foo();

const Foo& foo()const;

であるべきだと思ってます。うっかりしてました....

to38to38 2011/02/16 00:59 はじめまして。
ちょっと口を挟ませてください。

const Foo& foo(){return foo_;}

というメンバ関数がconstな参照を返している以上、Foo型の非constなメンバ関数が呼び出せないというのはデメリットというよりも当然なことのように思います。

メンバ変数の参照を返すことのデメリットというと、対象のメンバー変数(Hoge::foo_)の持ち方が変更されたときに、参照を返すことが出来なくなることくらいでしょうか?

ちなみに、メンバー変数の参照を返すのに、const参照を返すメンバー関数はconstなものにしておくのが定石だと思います。
非const参照を返すメンバー関数は非constなものにして、その両方は1つのクラス定義に共存できますので、

class Hoge
{
public:
const Foo& foo()const{return foo_;}
Foo& foo(){return foo_;}
private:
Foo foo_;
};
こんな感じになります。
なので、
bar( Hoge& h )
{
h.foo().fuga();
}
と、非constな場合はfuga()も呼ぶことが可能です。

mikoto1212mikoto1212 2011/02/16 01:09 コメントありがとうございます。うっかりconstメンバ関数にするのを忘れていました
(言い訳臭いですがこっち
http://d.hatena.ne.jp/mikoto1212/20110215/1297749017
の記事はconstメンバ関数です)。
なるほど、そのようなオーバーロードも可能なのですか、参考になります。
個人的には内側を書き換える場合はコピーを返してから代入を許したいですね(あくまで私の好みですが)。あ、でもnoncopyableなら参照を返さないとダメな場合があるのでその場合はそっちじゃないとダメですね(脳内完結失礼)。

nagoya313nagoya313 2011/02/16 13:38 const参照でメンバを返すと危ないのはこういう場合ですね。
例えばfooを特殊な形で初期化するHoge hogehoge();って関数があったとします。ここで
const Foo &f = hogehoge().foo();
とやってしまってしまうと、fが存在しないFooを指してしまうことになるの危ないのです。

mikoto1212mikoto1212 2011/02/16 15:33 コメントありがとうございます。
なるほど、確かにそれはデメリットとして存在しますねー。
試しにテストコードを書いてみましたが、メンバの持ち主であるクラスが死んでからも値を参照し続けました(値がまともに表示されているのも書き換えられてなかったからだと思います)。

教えていただきありがとうございました。

gintenlabogintenlabo 2011/02/16 23:50 std::vector とかの標準コンテナが参照返しを多用している以上、そこまで気を使わなくてもいい気がします。

mikoto1212mikoto1212 2011/02/17 00:15 コメントありがとうございます。
標準コンテナでもこの記述は使っているのですね....
とりあえずconst &で受け取るのには寿命延長効果もあるので注意したほうがよさそうです

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/mikoto1212/20110215/1297749017
Connection: close