2017-03-16 4 views
1

私が設計しているライブラリでは、クラスの大きなメンバ変数への読み込みアクセスが必要なことがあります。彼らのサイズのために、私はメンバーをコピーして返すゲッターを作りたくありません。私はそれらを外部から変更可能にしたくないので、それらを公開したり、それらへの参照を返すことはできません。安全にメンバ変数への参照を返します

class TestClass 
{ 
public: 
    explicit TestClass(double d): d_(d){} 

    const double& readD() const { return d_; } 

private: 
    double d_; 
}; 

(これは本当にダブルスのために意図されていない)誰かが参照をconst_castをして、データを直接アクセスすることができ

しかし、ここで:だから私は、私は、「リーダー」を使用するだろうと思いました。悪意を持っていなくても、データメンバへの参照を安全にして、元のオブジェクトが有効範囲外になった後もそのままにしておくことができます。私は、const参照は一時的な実行可能を保つことができますが、const_cast問題は削除されません。 は、だから私は、回避策を思い付いた:

Q1)効率のPOVからこれをどのように必要である:

#include <iostream> 

template<class T> 
class SafeMemberReference 
{ 
public: 
    using type = T; 
    SafeMemberReference(const T& t) :t(t) {} 
    explicit SafeMemberReference(T&& t) = delete; 

    operator const T&() && {return t; } 
    T get() && {return t; } 
private: 
    const T& t; 
}; 

class TestClass 
{ 
public: 
    explicit TestClass(double d): d_(d){} 

    SafeMemberReference<double> readD() const { return d_; } 

private: 
    double d_; 
}; 

int main() 
{ 
    TestClass foo(1.2); 

    // temporary from read can be used as temporary in expressions 
    std::cout << foo.readD() << std::endl; 

    // temporary can be used to copy from 
    auto x = foo.readD().get(); 

    // lvalue can not be used, so a possible dangling reference is no problem 
    auto ref = foo.readD(); 
    //std::cout << ref << std::endl; 
} 

私はこれまでいくつかの質問がありますか?私が返す最大のオブジェクトは、おそらく1000x1000の次元を持つ密な複雑な行列です。これらのコピーは頻繁に発生する可能性があります

Q2)&の返品に関する懸念はありますか?

Q3)これは良い解決策のようですか?それには欠点がありますか?

+1

'SafeMemberReference'はどのような問題を解決しますか?それは、不必要なコピーを避けることも、 'const_cast'を使って変更を防止することも避けていませんでした。コピーや 'const 'を直接返すこともできます。 – nwp

+0

作業するデータがあります。あなたはそれをカプセル化するクラスを持っています。なぜこのクラスのメソッドとして必要なすべてのデータ操作を実装しないのですか?データへの直接アクセスはありません。 – KonstantinL

答えて

4

言語自体と戦うためのあらゆる解決策は、良い解決策ではありません。

彼らはそのようにconst_castを使用した場合彼らはナックルにラップを取得する必要があります。もともとconstとして宣言されたオブジェクトにconst_cast経由でオブジェクトを変更しようとしている上の振る舞いは未定義です。あなたがそれを防ぐための解決策を導いても、敵対的プログラマはあなたのオブジェクトのアドレスを取って、そのアドレスをオフセットして(unsigned char*ポインタ演算を使って)、そのポインタを通してデータメンバを修正することができます!

もし私があなただったら、私は言語と戦わないでしょう。元の提案通りに私があなただったらconstの参照を返してください。

コード静的解析ツール/コンパイラの警告/コードレビュー/人事部門は、他の共同プログラマーをまっすぐに狭くするのに役立ちます。

+0

'const_cast'がOKである場合の詳細については、[cpp-reference](http://en.cppreference.com/w/cpp/language/const_cast)を読むことをお勧めします。 ...? "](http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used)、質問[ "const_castは安全ですか?"](http://stackoverflow.com/questions/357600/is-const-cast-safe) – TobiMcNamobi

+0

好奇心を要しない:OPの場合、これは実際には未定義の動作ですか? [const_castは安全ですか?](http://stackoverflow.com/q/357600/1683161)、元のオブジェクトが非const(OPの 'd_'は)である場合、' const_cast'は安全です。 – rainer

関連する問題