2011-01-06 10 views
15

std::stringのメンバーstrを持つクラスFooがあるとします。 get_strは何を返す必要がありますか?アクセサは値または定数参照を返す必要がありますか?

std::string Foo::get_str() const 
{ 
    return str; 
} 

または

const std::string& Foo::get_str() const 
{ 
    return str; 
} 

C++でより多くの慣用は何ですか?

+0

私は非常によく似た質問をしました:http://stackoverflow.com/questions/134731/returning-a-const-reference-to-an-object-instead-of-a-copy – Rob

+0

また、この[スタック交換提案](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "コードレビュー")を参照してください。ベータ版を開始する準備はほぼ完了ですが、もう少し必要です。 :) – greatwolf

答えて

14

短い答えは:あなたは、新しいstd::stringオブジェクトの作成を保存します。それは、(通常は)優れている参照を返すパフォーマンスの観点から:-)

を依存しています。 (この場合、作成にはかなりのコストがかかり、オブジェクトのサイズは が十分に高いので を正当化する必要があります。これは必ずしも考慮する必要はありませんが、これは必ずしもそうではありません。無視できるか、価値によって戻ってくるのは安いかもしれません)。

セキュリティの観点から、元の値のコピーを返すほうが、悪意のあるクライアントによってconstanceがキャストされる可能性があります。これは、メソッドがパブリックAPIの一部である場合、つまり返された値がどのように使用されているかについて完全に制御できない場合、特に考慮する必要があります。

+1

+1、これはかなり良い点です。実際、APIコードは、たとえ間接的にでもプライベートメンバーを公開するべきではありません。 –

+0

'std :: string'の長さはどれくらいですか?多くの実装では、短い 'std :: string'をコピーすることは安いです(あなたが何に対して反対しているかによって異なります)。 –

+0

@Charles、私はVisual C++プラットフォームで空の 'string'のサイズが20バイトであったことを覚えているようですが、もちろん実装依存です。私はパフォーマンスの利点が 'std :: string&'では常に明確であるとは言いませんでしたが、私の言い回しははっきりしていませんでした。 –

-1

戻り値の処理内容によって異なります。

これは、クエリを作成して、strを変更しない場合には、これより優れています。

そうでない場合は
const std::string& Foo::get_str() const 
{ 
    return str; 
} 

、このために行く:

std::string& Foo::get_str() 
{ 
    return str; 
} 

そして、あなたは、この使用し、strコピー/クローンをしたい場合:

std::string Foo::get_str() const 
{ 
    return str; 
} 
+0

これはすべての世界の中で最悪と思われるでしょうか?クライアントがオブジェクトのプライベートデータに直接アクセスできるようにします。私は間違いなく、第二のケースでは価値による返品に投票するだろう – davka

+0

@davka:あなたは正しい。 – Nawaz

+0

2番目のケースは、どちらも時間の多くと同等であるconst参照または値によって戻ってくる別のシナリオです。 – CashCow

1

私の知る限りの、ルールは同じです関数パラメータを値またはconst参照で取り込むかどうかを決定する際に使用されるものとして使用されます。 sizeof返される値が十分小さい場合、私はconst参照を返すコピーを返します。

+2

sizeof(std :: string)は十分に小さいですが、コピーの効率は文字列のサイズによって異なります –

+1

同じ問題はパラメータを返す値に影響しません。参照を返すには、関数が返された後に実際にオブジェクトを維持するために、呼び出されたエンティティが必要です。 'const'参照(通常)を取ることは、呼び出し側がオブジェクトを明確に定義された点まで維持すること、つまり関数の返りを必要とするだけです。 –

0

私は第2の実施(const参照)が正しいと信じて:返されるオブジェクトは不変であるため、カプセル化のルールを掲げ

  1. strのコピーがないので、少し効率的です。

しかし、最初のアプローチはほとんど同様に機能します。

7

アクセサーメソッドを使用する目的の1つは、インターフェイスからクラスの実装を抽象化することを少なくともある程度は試みることです。

参照オブジェクトに生涯の問題がないため、値を返す方が良いです。 std::stringメンバーを持っていないが、たとえばstd::stringstreamを持っているとか、またはstd::stringをオンザフライで作成しようとすると、インターフェースを変更する必要はありません。

返信:const参照はconst参照でパラメータを取ることの反対ではなく、constの値をとることは、内部データ表現を外部インターフェイスに結びつけません。

+0

生涯について+1良い点! –

+0

厳密に関数から返る目的のために、追加の 'std :: string'メンバーを持たないようにするものはありません。関数内でそれをコピーして返します。 –

+0

@ edA-qa mort-ora-y:これは当てはまりますが、メンテナンス(コードの複雑さ)と実行時のサイズのオーバーヘッドを意味します。 –

0

一般的にあなたが値でのPODを返す必要があります(例えば、int型、短い、文字、長いなど、)と、より複雑な型のためのconst参照:一般的に

int getData() const; 
short getMoreData() const; 
const std::string& getName() const; 
const ComplexObject& getComplexData() const; 
4

(実績のあるパフォーマンスの問題がありますしない限り)私は価値あるものに戻ります。

まず、意味の違いがあります。プロパティの変更によってクライアントが変更を更新したり、関数を呼び出す瞬間に値を取得したりしたい場合はどうすればよいでしょうか?

関数を呼び出すエンティティが参照を保持し、オブジェクトが破棄された後にその関数を使用する可能性があります(これはあまり良くありません)。

問題がたくさんあるために変数を更新している間に、スレッドがconst参照から読み込むと、別の問題が複数のスレッドコードで発生します。

いずれの場合でも、最も一般的な使用例は、関数の呼び出し側が変数に値を格納する場合です。

string val = obj->get_str(); 
// use val now 

これは(ない変数が存在しないcout << obj->get_str()とは反対に)真である場合は、必ずコンパイラはRVO値によるバージョンを実行することができますので、あなたが参照して戻ってしてもvalのための新しい文字列を構築する必要がありますby-const-ref変種を実行していません。結論として


あなたはそれがパフォーマンスの問題知っていると場合は、戻り値は、オブジェクトよりも長く保存されないことを確信しているを存在し、あなたが期待していません別のスレッドから使​​用するには、const参照で戻っても問題ありません。

+0

私はデフォルトで値を返すことに同意しませんが、マルチスレッドについてのあなたの要点は重要です。オブジェクトがスレッドセーフであれば、別のスレッドで変更可能なデータへの参照を返すべきではありません。 *いくつかの外部ロック機構はもちろんのこと* –

2

値を返すと、返すクラスのどこかにstd ::文字列を格納する必要がなくなります。

純粋な仮想メソッドでは、std :: stringがそこにあると想定せず、std :: stringを値で返す方が望ましいです。

明らかにstd :: stringメンバーがあり、その参照を返すだけの具体的なクラスでは、効率のためにconst参照で返すことができます。後で変更する必要がある場合でも、クラスを使用する機能を変更する必要はありません。

もちろん、コール間で内部文字列が変更されるマルチスレッドモデルでは、値を返す必要があります(クラスのユーザーがその時点で文字列値の「スナップショット」ビューを取得すると仮定します)コールの完了の)。

通常、参照により返信がより効率的です。私はしかし、あなたが効率的に値で返すことができ、私は非常に頻繁にそれを使用するために使用された非可変参照カウント文字列クラスを持っています。

ところで、std :: stringをconst値で返すことをお勧めします。ユーザーがローカル変数に「スワップ」するのを妨げるので、それを行うのが最良の方法だとは思わない。

関連する問題