我试图定义我的软件,这意味着并注意一些变量读/写访问一个好的设计。我在这里简化了讨论的计划。希望这对其他人也有帮助。 :-)的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