一部の変数への読み取り/書き込みアクセスに注意することを意味する、ソフトウェアの優れた設計を定義しようとしています。ここでは、議論のためにプログラムを単純化しました。うまくいけば、これは他の人にも役立つでしょう。:-)
次のようなクラス X があるとします。
class X {
int x;
public:
X(int y) : x(y) { }
void print() const { std::cout << "X::" << x << std::endl; }
void foo() { ++x; }
};
print()
また、将来、このクラスは X1、X2、... でサブクラス化され、 andを再実装できるとしましょうfoo()
。virtual
(これは私が直面している実際の問題ではないため、簡単にするためにここでは必要なキーワードを省略しました。)
ポリモーフィズムを使用するため、(スマート) ポインターを使用して単純なファクトリを定義しましょう。
using XPtr = std::shared_ptr<X>;
using ConstXPtr = std::shared_ptr<X const>;
XPtr createX(int x) { return std::make_shared<X>(x); }
これまでのところ、すべて問題ありません。どちらgoo(p)
が読み取りと書き込みが可能でp
、hoo(p)
どちらが読み取りのみ可能かを定義できますp
。
void goo(XPtr p) {
p->print();
p->foo();
p->print();
}
void hoo(ConstXPtr p) {
p->print();
// p->foo(); // ERROR :-)
}
呼び出しサイトは次のようになります。
XPtr p = createX(42);
goo(p);
hoo(p);
X( XPtr
) への共有ポインターは、その const バージョン ( ConstXPtr
)に自動的に変換されます。いいですね、まさに私が欲しいものです!
ここで問題が発生します: の異種コレクションが必要ですX
。私の選択はstd::vector<XPtr>
. (それは である可能性もありますlist
。なぜでしょうか。)
私が考えているデザインは以下です。コンテナーには 2 つのバージョンがあります。1 つは要素への読み取り/書き込みアクセス、もう 1 つは要素への読み取り専用アクセスです。
using XsPtr = std::vector<XPtr>;
using ConstXsPtr = std::vector<ConstXPtr>;
このデータを処理するクラスがあります。
class E {
XsPtr xs;
public:
E() {
for (auto i : { 2, 3, 5, 7, 11, 13 }) {
xs.emplace_back(createX(std::move(i)));
}
}
void loo() {
std::cout << "\n\nloo()" << std::endl;
ioo(toConst(xs));
joo(xs);
ioo(toConst(xs));
}
void moo() const {
std::cout << "\n\nmoo()" << std::endl;
ioo(toConst(xs));
joo(xs); // Should not be allowed
ioo(toConst(xs));
}
};
ioo()
および関数は次のjoo()
とおりです。
void ioo(ConstXsPtr xs) {
for (auto p : xs) {
p->print();
// p->foo(); // ERROR :-)
}
}
void joo(XsPtr xs) {
for (auto p: xs) {
p->foo();
}
}
ご覧のとおり、 inE::loo()
でE::moo()
次のように変換する必要がありますtoConst()
。
ConstXsPtr toConst(XsPtr xs) {
ConstXsPtr cxs(xs.size());
std::copy(std::begin(xs), std::end(xs), std::begin(cxs));
return cxs;
}
しかし、それはすべてを何度もコピーすることを意味します.... :-/
また、moo()
const である では、のデータjoo()
を変更するを呼び出すことができます。xs
私が欲しかったものではありません。ここでは、コンパイル エラーを優先します。
完全なコードはideone.comで入手できます。
問題は、ベクトルを const バージョンにコピーせずに同じことを行うことは可能ですか? または、より一般的に、効率的で理解しやすい優れたテクニック/パターンはありますか?
ありがとうございました。:-)