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>

查看:162
本文介绍了shared_ptr< T>到shared_ptr< T const>和向量T向量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&lt; T&gt;到shared_ptr&lt; T const&gt;和向量T向量T const的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆