【发布时间】:2013-10-27 09:36:16
【问题描述】:
我正在尝试为我的软件定义一个好的设计,这意味着要小心对某些变量的读/写访问。在这里,我简化了讨论的程序。希望这对其他人也有帮助。 :-)
假设我们有一个如下的类 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::adaptors::transformed的const-view 和适当的函数对象来转换您的共享指针。 -
@Xeo:我已经快速查看了
boost::adaptors::transformed,但似乎我必须在某些时候复制一些东西,有点像上面,但语法不同,对吧?如果不是这样,您介意在下面举一个例子吗? :-) -
只是一个注释。你的
std::move(i)不会移动任何东西。move不动,只是演员阵容。也许它只是从复制你的实际代码到它移动的地方:)
标签: c++ c++11 constants shared-ptr stdvector