简体   繁体   English

stl容器中的C ++ 11 shared_pointer常量

[英]C++11 shared_pointer constness within stl containers

I have the following problem and I wonder whether there's a better way to solve it: 我有以下问题,我想知道是否有更好的方法来解决:

class myObj {
public:
    typedef std::shared_ptr<myObj> handle;
    typedef std::shared_ptr<const myObj> const_handle;
    int someMethod() { ... }
    int someConstMethod() const { ... }
};

Now what I need is a container class that somehow allows you to modify or read a collection of myObj depending on its own const ness, like so: 现在,我需要的是一个容器类,该容器类可以使您根据自身的const来修改或读取myObj的集合,如下所示:

class myCollection {
public:
    typedef std::list<myObj::handle> objList;
    typedef std::list<myObj::const_handle> const_objList;

    inline objList& modify() { return _obl; }

    // it would be nice to do this, but it won't compile as 
    // objList and const_objList are completely different types
    inline const_objList& read() const { return _obl; } // doh! compile error...

    // returning a const objList won't help either as it would return non-const
    // handles, obviously.

    // so I am forced to do this, which sucks as i have to create a new list and copy
    void read(const_objList &l) {
        std::for_each(
            _obl.begin(), 
            _obl.end(), 
            [&l] (myObj::handle &h) { l.push_back(h); } 
            // ok as handle can be cast to const_handle
        ); // for_each
    }

private:
    objList _obl;
};

So this solution actually works as a const myCollection would only allow you to get a list of const_handle which only allows you to call non-modifying methods of myObj (GOOD). 因此,此解决方案实际上是作为const myCollection const_handle ,它仅允许您获取const_handle的列表,该列表仅允许您调用myObj非修改方法(GOOD)。

The problem is that the " read " method is really ugly (BAD). 问题是“ read ”方法确实很丑陋(BAD)。

Another method would be to expose somehow the list methods and return const_handle and handle as needed but it's a lot of overhead, especially if you want to use something more complex than a list. 另一种方法是以某种方式公开list方法并根据需要返回const_handle和handle,但这会产生大量开销,特别是如果您想使用比列表更复杂的东西。

Any idea? 任何想法?

Given what you stated that you want to accomplish, I don't think that your solution is too bad. 鉴于您所说的要完成的工作,我认为您的解决方案并不算太糟糕。 Imagine that some other code may be modifying the internal collection, like adding or removing values. 想象一下,其他一些代码可能正在修改内部集合,例如添加或删除值。 Returning a copy of the current state of the collection is safe for client code, since it can work on the copy, without the danger of element being deleted in the meantime. 对于客户端代码来说,返回集合当前状态的副本是安全的,因为它可以在副本上工作,而同时没有删除元素的危险。 But I digress, this is getting into threading issues and may not be relevant. 但我离题,这正在涉及线程问题,可能不相关。

You could use prettier: 您可以使用更漂亮的:

  inline const_objList read()  const
   { 
       const_objList cl(_obl.begin(), _obl.end());
       return cl; 
   } 

However, I do think that your problems derive from mixing two types of constness: constness of the members of the collection versus the constness of the collection itself. 但是,我确实认为您的问题来自混合两种类型的constness:集合成员的constness与集合本身的constness。

Instead of Modify and Read methods, that deal with the list as a whole, I would try exposing const and non-const iterators to internal list, through corresponding const and non-const methods returning said iterators. 我会尝试通过将相应的const和non-const方法返回给内部迭代器,而不是将Modify和Read方法作为一个整体来处理列表,而是尝试将const和non-const迭代器暴露给内部列表。

But this immediately begs the question: why then have myCollection in the first place? 但这立即引出了一个问题:为什么首先要有myCollection

Creating entirely new collection type around std::list doesn't seem needed, unless you get a lot of proverbial bang for the buck from other, added functionality that is not visible in your sample. 似乎不需要在std :: list周围创建全新的集合类型,除非您从其他示例中看不到的其他已添加功能中获得了很多好处。

You can then make your added functionality free methods that take std::list of your handles as the input. 然后,您可以使添加的功能免费的方法以std :: list的句柄为输入。 Not everything requires an object and operations on objects need not necessarily be member methods, unless access to private data is required. 并非所有内容都需要对象,并且对象上的操作不一定是成员方法,除非需要访问私有数据。

You mentioned maybe using another container instead of the list. 您提到可能使用另一个容器而不是列表。 But your class, as is, won't do it, unless you have a template, where template parameter can be one of STL containers. 但是,除非有模板,否则您的类不会这样做,其中模板参数可以是STL容器之一。 Which then implies that you should expose iterators. 这意味着您应该公开迭代器。 Namely, if you foresee changing the internal collection type, you would want to make the public interface to myCollection transparent regarding the collection type. 即,如果您预见到将更改内部集合类型,则需要使与集合类型有关的myCollection的公共接口透明。 Otherwise, clients will have to recompile each time you change your mind about the internal implementation. 否则,每次您改变对内部实现的态度时,客户端都将不得不重新编译。

EDIT -----

Finally, if implementing iterators (while interesting and most correct) is too much, why not go for simple getters like in this SO post: 最后,如果实现迭代器(虽然有趣且最正确)太多了,为什么不去简单的getters呢?

smart pointer const correctness 智能指针const正确性

I'll quote the topmost answer by Rüdiger Stevens (it assumes vector instead of list): 我将引用RüdigerStevens给出的最高答案(它假设使用向量而不是列表):

template <typename T>
class MyExample
{
  private:
    vector<shared_ptr<T> > data;

  public:
    shared_ptr<const T> get(int idx) const
    {
      return data[idx];
    }
    shared_ptr<T> get(int idx)
    {
      return data[idx];
    }
    void add(shared_ptr<T> value)
    {
      data.push_back(value);
    }
};

A list-of-pointers-to-T is not a list-of-pointers-to-constant-T. 指向T的指针列表不是恒定T的指针列表。

std::list<std::shared_ptr<int>> a;
std::list<std::shared_ptr<const int>>& ra = a; // illegal but imagine it's not
std::shared_ptr<const int> x = std::make_shared<const int>(42);
ra.push_back(x); // totally legal, right?
++**a.begin(); // oops... just incremented a const int

Now a list-of-pointers-to-T is, conceptually, a constant-list-of-constant-pointers-to-constant-T, but std::list<std::shared_ptr<T>> does not support such a deep const propagation. 现在,从概念上讲,指向T的指针列表是恒定T的常量列表,但是std::list<std::shared_ptr<T>>不支持深入的const传播。 const std::list<std::shared_ptr<T>> contains constant pointers to non-constant objects. const std::list<std::shared_ptr<T>>包含指向非常量对象的常量指针。

You can write your own variant of list<> or your own variant of shared_ptr<> that have such support. 您可以编写自己的list<>的变体, 或者自己的shared_ptr<>的变体,都具有这种支持。 It probably won't be very easy though. 不过,这可能并不容易。 A const_propagating_shared_ptr is probably the easier of the two. const_propagating_shared_ptr可能是两者中较容易的。 It would have to encapsulate an std::shared_ptr<T> object and forward almost everything to it as-is. 它必须封装一个std::shared_ptr<T>对象,并将几乎所有内容都按原样转发给它。 As opposed to std::shared_ptr<T> it would have separate const and non- const versions of operator-> , operator*() and get() . 至于反对std::shared_ptr<T>这将有单独的const和非const版本operator->operator*()get()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM