c++ - shared_ptr<T> 到 shared_ptr<T const> 和 vector<T> 到 vector<T const>

标签 c++ c++11 constants shared-ptr stdvector

我正在尝试为我的软件定义一个好的设计,这意味着要小心对某些变量的读/写访问。这里我简化了讨论的程序。希望这对其他人也有帮助。 :-)

假设我们有一个类 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)可以读写phoo(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 ) 自动转换为其常量版本 ( 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 获得.

问题是:是否可以在不将 vector 复制到其 const 版本的情况下执行相同的操作?或者,更一般地说,是否有既高效又易于理解的好技术/模式?

谢谢。 :-)

最佳答案

我认为通常的答案是对于类模板 X<T> , 任何 X<const T>可以专门化,因此不允许编译器简单地假设它可以转换 X<T> 的指针或引用至 X<const T>并且没有通用的方式来表达这两个实际上是可转换的。但后来我想:等等,有一种方法可以说 X<T> 是一个 X<const T> . IS A 通过继承来表达。

虽然这对 std::shared_ptr 没有帮助或标准容器,这是您在实现自己的类时可能希望使用的一种技术。事实上,我想知道是否std::shared_ptr并且可以/应该改进容器以支持这一点。谁能看出这有什么问题吗?

我想到的技术会像这样工作:

template< typename T > struct my_ptr : my_ptr< const T >
{
    using my_ptr< const T >::my_ptr;
    T& operator*() const { return *this->p_; }
};

template< typename T > struct my_ptr< const T >
{
protected:
    T* p_;

public:
    explicit my_ptr( T* p )
      : p_(p)
    {
    }

    // just to test nothing is copied
    my_ptr( const my_ptr& p ) = delete;

    ~my_ptr()
    {
        delete p_;
    }

    const T& operator*() const { return *p_; }
};

Live example

关于c++ - shared_ptr<T> 到 shared_ptr<T const> 和 vector<T> 到 vector<T const>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19616586/

相关文章:

c++ - 使用提示将排序范围插入 std::set

MySQL常量表

c++ - 从 C++ 中的 int 指针返回只读指针

c++ - VS2013 : STL regex class crashes when regular expression contains\

c++ - apply_visitor 不改变对象

c++ - C++中的无序集合,为什么需要散列?

c++ - 为什么我的 for 循环在 double vector 上崩溃?

c++ - C2556 : overloaded function differs only by return type

c++ - 如何在 C++ 程序中包含流程工具?

c++ - 在同一指令中引用和取消引用