26

重複の可能性:
const オブジェクトを返す必要がありますか?
(その質問の元のタイトルは、int foo() or const int foo()?で、なぜ見逃したのかを説明しています。)


効果的な C++、項目 3: 可能な限り const を使用します。特に、 const オブジェクトを返すことは、 のような意図しない代入を避けるために促進されif (a*b = c) {ます。私はそれが少し妄想的だと思いますが、それでも私はこのアドバイスに従っています.

const オブジェクトを返すと、C++11 でパフォーマンスが低下する可能性があるように思えます。

#include <iostream>
using namespace std;

class C {
public:
    C() : v(nullptr) { }

    C& operator=(const C& other) {
        cout << "copy" << endl;
        // copy contents of v[]
        return *this;
    }

    C& operator=(C&& other) {
        cout << "move" << endl;
        v = other.v, other.v = nullptr;
        return *this;
    }

private:
    int* v;
};

const C const_is_returned() { return C(); }

C nonconst_is_returned() { return C(); }

int main(int argc, char* argv[]) {
    C c;
    c = const_is_returned();
    c = nonconst_is_returned();
    return 0;
}

これは以下を出力します:

copy
move

移動割り当てを正しく実装していますか? それとも、C++11 で const オブジェクトを返すべきではありませんか?

4

3 に答える 3

26

constオブジェクトを返すことは、他の問題を引き起こす可能性がある回避策です。C++11以降、割り当ての問題に対するより良い解決策があります:メンバー関数の参照修飾子。私はいくつかのコードでそれを説明しようとします:

int foo(); // function declaration
foo() = 42; // ERROR

int2 行目の割り当てにより、 C と C++ の両方で組み込み型のコンパイル時エラーが発生します。他の組み込み型についても同様です。これは、組み込み型の代入演算子が左辺に非 const 左辺値参照を必要とするためです。コードに入れると、代入演算子は次のようになります (無効なコード)。

int& operator=(int& lhs, const int& rhs);

C++ では、パラメーターを左辺値参照に制限することが常に可能でした。ただし、メンバー関数の暗黙的な最初のパラメーター ( ) については、C++11 までは不可能でした*this

これは C++11 で変更されました。メンバー関数の const 修飾子と同様に、メンバー関数の参照修飾子が追加れました。&次のコードは、copy および move 演算子の使用法を示しています (パラメーター リストの後に注意してください)。

struct Int
{
    Int(const Int& rhs) = default;
    Int(Int&& rhs) noexcept = default;
    ~Int() noexcept = default;
    auto operator=(const Int& rhs) & -> Int& = default;
    auto operator=(Int&& rhs) & noexcept -> Int& = default;
};

このクラス宣言では、次のコード フラグメントの代入式は無効になりますが、最初の例のように、ローカル変数への代入は機能します。

Int bar();
Int baz();
bar() = baz(); // ERROR: no viable overloaded '='

したがって、const オブジェクトを返す必要はありません。代入演算子を左辺値参照に制限して、他のすべてが期待どおりに機能するようにすることができます (特に移動操作)。

以下も参照してください。

于 2012-10-27T12:01:17.107 に答える
25

値によってconstオブジェクトを返すことは、C++11 より前であっても、あまり良い考えではありませんでした。唯一の効果は、返されたオブジェクトに対して呼び出し元が非 const 関数を呼び出せないようにすることですが、呼び出し元がオブジェクトのコピーを受け取ったことを考えると、これはあまり関係ありません。

定数オブジェクトが返されると、呼び出し元がそれを誤って使用すること (たとえば、比較の代わりに誤って代入を行うなど) が防止されることは事実ですが、返されたオブジェクトを呼び出し元がどのように使用できるかを決定するのは、関数の責任であってはなりません (返されるオブジェクトが、関数が所有する構造体への参照またはポインターでない限り)。関数の実装者は、返されたオブジェクトが比較で使用されるのか、それとも別の目的で使用されるのかを知ることはできません。

constまた、C++ 11 では、 a を返すと効果的に移動操作が妨げられるため、問題がさらに深刻であることも正しいです。(ただし、コピー/移動の省略は防げません。)

もちろんconst、関数が参照またはポインターを返す場合でも、これは非常に便利です (パラノイアの兆候はありません)。

于 2012-10-27T12:12:49.517 に答える
3

呼び出しがconst_is_returnedトリガーされるのcopy constructorは、オブジェクトを変更move constructorするmove必要があるため、オブジェクトでは使用できないためconstです。constどのような場合でも使用は推奨されず、プログラマーの判断に従うべきだと私は言いがちです。良い質問。

于 2012-10-27T11:59:51.250 に答える