shared_ptr< T>到shared_ptr< T const>和向量T向量T const [英] shared_ptr<T> to shared_ptr<T const> and vector<T> to vector<T const>
问题描述
我正在尝试为我的软件定义一个好的设计,这意味着要谨慎地对某些变量进行读/写访问。在这里,我简化了讨论程序。希望这对其他人也有帮助。 :-)
I'm trying to define a good design for my software which implies being careful about read/write access to some variables. Here I simplified the program for the discussion. Hopefully this will be also helpful to others. :-)
假设我们有一个X类,如下所示:
Let's say we have a class X as follow:
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
关键字,因为这不是我要面对的实际问题。)
Let's also say that in the future this class will be subclassed with X1, X2, ... which can reimplement print()
and foo()
. (I omitted the required virtual
keywords for simplicity here since it's not the actual issue I'm facing.)
因为我们将使用多态性,所以我们使用(智能)指针并定义一个简单的工厂:
Since we will use polymorphisme, let's use (smart) pointers and define a simple factory:
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
。
Until now, everything is fine: I can define goo(p)
which can read and write p
and hoo(p)
which can only read 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
)。很好,这正是我想要的!
The shared pointer to X (XPtr
) is automatically converted to its const version (ConstXPtr
). Nice, it's exactly what I want!
现在麻烦了:我需要一个 X
的异构集合。我的选择是 std :: vector< XPtr>
。 (也可以是列表
,为什么不这样。)
Now come the troubles: I need a heterogeneous collection of X
. My choice is a std::vector<XPtr>
. (It could also be a list
, why not.)
我想到的设计如下。我有两种版本的容器:一种具有对其元素的读/写访问权限,一种具有对其元素的只读访问权限。
The design I have in mind is the following. I have two versions of the container: one with read/write access to its elements, one with read-only access to its elements.
using XsPtr = std::vector<XPtr>;
using ConstXsPtr = std::vector<ConstXPtr>;
我有一个处理该数据的类:
I've got a class that handles this data:
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()进行一些转换
:
As you can see, in E::loo()
and E::moo()
I have to do some conversion with toConst()
:
ConstXsPtr toConst(XsPtr xs) {
ConstXsPtr cxs(xs.size());
std::copy(std::begin(xs), std::end(xs), std::begin(cxs));
return cxs;
}
但这意味着要一遍又一遍地复制所有内容....:-/
But that means copying everything over and over.... :-/
此外,在 moo()
(即const)中,我可以调用 joo()
会修改 xs
的数据。不是我想要的这里我更喜欢编译错误。
Also, in moo()
, which is const, I can call joo()
which will modify xs
's data. Not what I wanted. Here I would prefer a compilation error.
完整的代码可在中找到。 ideone.com 。
问题是:是否可以执行相同的操作而不将向量复制到其const版本?或者,更笼统地说,有没有一种既有效又易于理解的好的技术/模式?
谢谢。 :-)
推荐答案
基于评论和答案,我最终为容器创建了一个视图。
Based on the comments and answers, I ended up creating a views for containers.
基本上,我定义了新的迭代器。我在github上创建了一个项目: mantognini / ContainerView 。
Basically I defined new iterators. I create a project on github here: mantognini/ContainerView.
可能可以改进代码,但是主要思想是拥有两个模板类, View
和 ConstView
,在具有 begin()
和<$的现有容器(例如 std :: vector< T>
)上c $ c> end()用于在基础容器上进行迭代的方法。
The code can probably be improved but the main idea is to have two template classes, View
and ConstView
, on an existing container (e.g. std::vector<T>
) that has a begin()
and end()
method for iterating on the underlying container.
有一点继承(视图
是 ConstView
),它有助于在需要时将读写模式转换为只读视图,而无需额外的代码。
With a little bit of inheritance (View
is a ConstView
) it helps converting read-write with to read-only view when needed without extra code.
由于我不喜欢指针,因此我使用模板专门化来隐藏 std :: shared_ptr
:<$ c $容器上的视图c> std :: shared_ptr< T> 不需要额外的解引用。 (因为我不使用原始指针,所以我还没有实现它。)
Since I don't like pointers, I used template specialization to hide std::shared_ptr
: a view on a container of std::shared_ptr<T>
won't required extra dereferencing. (I haven't implemented it yet for raw pointers since I don't use them.)
这篇关于shared_ptr< T>到shared_ptr< T const>和向量T向量T const的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!