質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

7回答

3008閲覧

非constな参照は使わないほうがよい??

torimingo

総合スコア122

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

6クリップ

投稿2019/09/01 08:26

いくつかのサイトで「非constな参照を使うと、コードがわかりにくくなるから使わないほうがよい。参照はconstにすべし。間接的に値を変更したいのであれば、参照ではなくポインタを使ったほうがよい」というようなことが書かれていました。
自分には、参照もポインタも同じようなものにみえます。
非constな参照は、本当に使わないほうがよいのでしょうか??

LouiS0616👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答7

0

ベストアンサー

非constな参照は、本当に使わないほうがよいのでしょうか??

特定の文脈を指しているか分からなかったので、大まかなガイドラインを提示してみます。いずれも C++ Core Guidelines をベースとしています。(あくまでガイドラインの一つですから、個人/プロジェクト/開発組織の事情で調整ください。)

  • ローカル変数型:**デフォルトで「const参照型」**を検討しつつ、オブジェクトを変更するケースでは非const参照型を利用します。例:範囲for文でのfor (const auto& e: c)for (auto&& e: c)など。
  • 関数の引数型:**デフォルトで「const参照型」**を検討をすべきです。“In-Out引数”のように用いるケースでは「非const参照型」が使えるかもしれません。"引数無し"もとりうるケースでは「ポインタ型」を、型サイズが小さい場合は「値型(T)」も検討ください。
  • 関数の戻り値型:参照型の場合は戻り値オブジェクトの生存期間(lifetime)と所有権(ownership)について十分注意する必要があります。メンバ関数で*this参照を返す場合は、const/非constは動作セマンティクスに合わせて選択します。
  • クラスのメンバ変数型:参照型よりも値型(T)やスマートポインタ(shared_ptr<T>,unique_ptr<T>)を検討すべきです。オブジェクトの生存期間(lifetime)と所有権(ownership)について十分注意する必要があります。

関連するガイドライン項目:

  • I.11: Never transfer ownership by a raw pointer (T*) or reference (T&)
  • F.16: For "in" parameters, pass cheaply-copied types by value and others by reference to const
  • F.17: For "in-out" parameters, pass by reference to non-const
  • F.43: Never (directly or indirectly) return a pointer or a reference to a local object
  • F.44: Return a T& when copy is undesirable and "returning no object" isn't needed
  • F.60: Prefer T* over T& when "no argument" is a valid option
  • C.32: If a class has a raw pointer (T*) or reference (T&), consider whether it might be owning
  • C.145: Access polymorphic objects through pointers and references
  • R.4: A raw reference (a T&) is non-owning
  • R.37: Do not pass a pointer or reference obtained from an aliased smart pointer
  • CP.31: Pass small amounts of data between threads by value, rather than by reference or pointer
  • Con.3: By default, pass pointers and references to consts

投稿2019/09/02 04:03

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 05:35

ご回答ありがとうございます。 非constな参照の使用についてガイドラインを示して頂きましたので、ベストアンサーとさせて頂きます。
guest

0

非constな参照は、本当に使わないほうがよいのでしょうか??

好みの問題じゃないかしらね。

「コードがわかりにくくなるから使わないほうがよい」の裏返しは
「コードがわかりにくくならないなら使っていい」だろうから。

投稿2019/09/01 08:51

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 03:23

ご回答ありがとうございます。 たしかに、おっしゃる通りだと思います。 「参照はconstにすべし」と、格言のように書かれているサイトがいくつかあったので、もやもやしていました・・・。
guest

0

こんにちは。

自分には、参照もポインタも同じようなものにみえます。

私も「同じようなもの」として捉えています。そして、参照はポインタの機能制限版です。
制限された機能で十分なケースでは制限されていた方がデバッグが捗ります。

int* foo;int& foo;は似たような機能を提供してくれます。
最大の相違点は前者はnullptrで容易に初期化できますが、後者はかなり変な記述をしないとできません。(そもそも未定義動作を引き起こしますし。)
ですので、私は可能な時は後者を使います。これにより、間違ってnullptrを渡すようなコードを事実上かけなくなりますので、デバッグの時にそれを疑う必要がなくなり開発が捗ります。

投稿2019/09/01 09:47

Chironian

総合スコア23274

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 03:19

ご回答ありがとうございます。 「関数の引数に、constではない参照を指定する」ということも十分有り得るということになりますか?
Chironian

2019/09/10 02:23 編集

その通りです。nullptrを渡す必要がなく、かつ、戻り値以外にも値を返却したいケースでは、私は非const参照を使ってます。
guest

0

まあ宗教戦争ではありますが、個人的にはポインタは使うべきではないと考えます。

ポインタを引数に使った瞬間、その関数でNULLチェックをする義務が生じます。でももしNULLだった場合どうやって呼び出し側に通知しましょうか?例外だと実行コストが重すぎですね、std::optionalのようななにかだとエラー内容が伝わりません。std::error_codeを返すのも手ですがだいぶ面倒くさいです。
仮にこうしてどうにかエラー通知を組んでも、例外以外では呼び出し側でNULLを渡してたらどうするという処理を書かないといけませんね、めんdです。

と考えていくと、そもそもNULLチェックの責任は関数の呼び出し側にあるべきです。これを要求できるのが参照を使う強みです。

投稿2019/09/02 00:41

yumetodo

総合スコア5852

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 03:16 編集

ご回答ありがとうございます。 ポインタを使わず参照しか使わない、ということですと「関数の引数はconstではない参照でも特に問題ない」ということにもなりますか? 参照は再割当てできない、という記事をどこかで読んだのですが、再割当てしたいときは、やむを得ずポインタを使うようにするという感じですかね。
guest

0

どう活用するかは個人の能力次第です。
チーム開発では護送船団方式にならざるを得ないので、望みを叶えてあげれば評判は上がります。
生産性は落ちます。

投稿2019/09/09 23:08

kendji

総合スコア92

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

「一方のみを使って,他方を忌避した方がよい」という宗教じみた考え方は違う感.
性質が異なる物が2種類存在するのなら,やりたいことに適する方を使う(使い分け).

void F( XXX &rXXX ); //引数が参照

という関数があるとしたら,それは
「引数には,真っ当に生成されたオブジェクトを渡せ.当該オブジェクトは関数内で変更され得る」
ということを表現しているのであり,

void F( XXX *pXXX ); //引数がポインタ

という関数があるとしたら,それは
「引数がオブジェクトを指す場合には,当該オブジェクトは関数内で変更され得る.引数にnullptrを渡した場合にどうなるのか?に関してはリファレンスなり注釈なりでしっかりと確認されたい」
ということを表現しているのだと考えます.

投稿2019/09/02 03:43

fana

総合スコア12151

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 03:52

ご回答ありがとうございます。 用途によっては、「関数の引数として、constではない参照を使っても特に問題ない」ということになりますか?
fana

2019/09/02 04:14

「constでない参照」が用途上妥当なのであれば,それが妥当なのだから,何も問題ない. (質問文にある「わかりにくい」という謎の主張を除いては,ということになりますが.)
guest

0

C言語を主にやっていた人からするとインスタンスを引数に指定したときぱっと見では参照渡しが行われたのか値渡しによりインスタンスのコピーが行われたのか分かりにくいからだと思います。
ポインタであればインスタンスのコピーは発生しないのでそれだけで安心です。

自分が設計する場合は参照渡しを使うのはoperatorの実装で必要な時のみでそれ以外の関数であればconstだろうが非constだろうがポインタ指定にします。

投稿2019/09/01 08:50

nomuken

総合スコア1627

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/09/02 03:26

ご回答ありがとうございます。 自分もC言語から入ったので、ポインタのほうが見やすいのは同感です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問