2017-01-18 15 views
1

私はクラスのメンバに割り当てられた非const参照をとるコンストラクタを持つクラスを持っています。今私は、上記のクラスのconstオブジェクトを作成するが、私はコンストラクタにconstリファレンスを渡す場合、コンストラクタは、文句を言う。私の元のコードを単純化した以下のコードは、この問題を示しています。非constを使用したconstオブジェクトの作成

constデータをベースにしているので、constオブジェクトの作成に問題はありません。

私はcreate_const_aで何をしようとしていますか?

#include <iostream> 

class A { 
private: 
    double &d; 
    const int &i; 
public: 
    A(double &dd, const int &ii) 
    : d(dd), i(ii) 
    {} 

    void set_d(double a) { 
    d = a; 
    } 

    void print() const { 
    std::cout << d << " " << i << std::endl; 
    } 
}; 


A create_a(double &dd, const int &ii) { 
    return A(dd,ii); 
} 

const A create_const_a(const double &dd, const int &ii) { 
    return A(dd,ii); 
} 


void foo(A a) 
{ 
    a.set_d(1.3); 
    a.print(); 
} 

void bar(const A a) 
{ 
    a.print(); 
} 


int main(int argc, char *argv[]) 
{ 
    double d = 5.1; 
    int i = 13; 

    foo(create_a(d,i)); 

    bar(create_const_a(d,i)); 

    return 0; 
} 

私が手にエラーがある:

test.cc: In function ‘const A create_const_a(const double&, const int&)’: 
test.cc:27:17: error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers 
    return A(dd,ii); 
       ^
test.cc:8:3: note: initializing argument 1 of ‘A::A(double&, const int&)’ 
    A(double &dd, const int &ii) 
^

更新:constのオブジェクトとその中の非const参照でどのように機能するかについて、いくつか新しいことを学んだ後、私は最終的に元の問題を解決しました別のタイプ、例えばConstAを導入することで、問題のあるケースで使用できるconst参照のみが含まれています。

+1

非constからconstに変更できますが、その逆は変更できません。コンストラクタは非constを必要とし、 'create_const_a'はc​​onstを受け取ります。 – AndyG

+5

これらのすべての参考文献...続行すると、遅かれ早かれ、参照が足りなくて悪いことが起こるようなポインタが出てくるでしょう。 *なぜあなたは 'A'クラスのリファレンスを持っていますか?このような解決策で解決しようとしている*実際の問題は何ですか? –

+1

'create_const_a'メソッドがローカルオブジェクトへの参照を返しています。これは、あなたが思っているように見えるようには機能しません。詳細については、[この回答](http://stackoverflow.com/a/4643721/7359094)を参照してください。 –

答えて

1

constの非constへの変換を避けるために、これは禁止されています。ここで

はこれが起こるだろうかの小さな例です:a = 5fooオブジェクトの状態を変更しないので

struct foo { 
    int& a; 
    foo(int& b) : a(b) {} 
    void bar() const { 
     a = 5; 
    } 
}; 

上記は、うまくコンパイルします。それは外部の状態を変更しますint、従ってfoo::barconstになることができます。

は今、私たちはこれを行うことができることを前提としています

const foo make_const(const int& x) { 
    return foo(x); // Not allowed 
} 

その後、我々は

const foo f(make_const(10)); 
f.bar(); 

を書いて、未定義の動作で一時的intへの参照を変更することができるだろう。ここで

は小さなdemoです:

int x = 10; 
cout << x << endl; 
const foo f(x); 
f.bar(); 
cout << x << endl; 

それはあなたがconstネスドロップしようとしている

10 
5 
+0

参照がconst-correctnessに違反することなく変更できるという事実は私には全く新しいもので、なぜこれが不可能に思えるかについて多くのことが説明されています。 – kalj

+0

@kaljこれは、参照とポインタに適用されるときに 'const'-nessの最も難しい部分です。ポインターまたは参照は、それらがポイント/参照する項目が書き込み可能なままである間に、「const」とすることができる。 – dasblinkenlight

0

を出力しますので、

const A create_const_a(const double &dd, const int &ii) { 
    return A(dd,ii); 
} 

しかしddは非constです作成されたオブジェクトAは私には分かりませんdのメンバーを変更することはできませんが、create_const_aの発信者はそれを信じている変数を渡します。

ddのコピーを作成しないでください。また、危険で設計上の誤りを強く示しているconst(たとえば、const_cast)を削除することはできません。

Aの定義には「dを変更する必要があります」と表示されていますが、create_constでは変更されないことを約束します。

つまり、デザインのエラーを解決する必要があります。制約を解除するかコピーを作成します。契約の違反が波及したときに本当の問題に遭遇するまで、「エラーが消え去る」ことは、悪い設計の症状を沈黙させるだけです。

0

ファンクションconst A create_const_aは、最初の引数としてconst doubleを参照し、それをctorで非const refとして使用しようとします。

ここでconst修飾子を削除する必要があります。

あなたはここでそれを行うことができる理由の本当に確信している場合、あなたはcreate_constはオールウェイズ非constのパラメータを受け取ることを確認することができます場合は、あなたが明示的に修飾子を削除するconst_castを使用できることを意味します:

const A create_const_a(const double &dd, const int &ii) { 
    return A(const_cast<double &>(dd),ii); 
} 

しかし、BEWAREの場合は、最初にconstとして宣言された変数に対して、未定義の動作が発生します。

関連する問題