我試圖定義我的軟件,這意味着並注意一些變量讀/寫訪問一個好的設計。我在這裏簡化了討論的計劃。希望這對其他人也有幫助。 :-)的shared_ptr <T>到shared_ptr <T const>和矢量<T>到矢量<T const>
比方說,我們有一個類X如下:
class X {
int x;
public:
X(int y) : x(y) { }
void print() const { std::cout << "X::" << x << std::endl; }
void foo() { ++x; }
};
我們也可以說,在未來這一類將與X1,X2,被繼承...可以重新實現print()
和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
,爲什麼不)。
我想到的設計是以下幾點。我有兩個版本的容器:一個對其元素具有讀/寫訪問權限,另一個對其元素進行只讀訪問。
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();
}
}
正如你所看到的,在E::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()
,這是常量,我可以叫joo()
將修改xs
的數據。不是我想要的。在這裏,我寧願編譯錯誤。
完整的代碼在ideone.com。
問題是:是否有可能做到這一點,但沒有將矢量複製到它的const版本?或者更一般地說,是否有一種既高效又易於理解的良好技術/模式?
謝謝。 :-)
獲取'boost :: adapters :: transformed'的'const'-view和一個appropri吃了功能對象來轉換你的共享指針。 – Xeo
@Xeo:我很快看了'boost :: adapters :: transformed',但是似乎我必須在某些時候複製東西,有點像上面的但有不同的語法,對吧?如果情況並非如此,您是否介意在下面舉個例子? :-) – Hiura
只是一個說明。你的'std :: move(i)'不會移動任何東西。 「移動」不移動,它只是一個演員。也許這只是從你的實際代碼複製到它的位置:) – typ1232