首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有共享所有者语义的容器

具有共享所有者语义的容器
EN

Stack Overflow用户
提问于 2017-02-25 23:40:14
回答 1查看 49关注 0票数 0

我正在设计一个具有共享所有权语义的容器类型。它支持切片,因此片共享所有权。我的一个问题是,数据共享似乎干扰了const的正确性,所以我试图关注这一点,但我对结果并不满意。

下面是我的实际代码的一个非常坏的版本:

代码语言:javascript
复制
#include <memory>
#include <vector>
#include <algorithm>

template <typename T>
class SharedMem
{
public:
    SharedMem(std::initializer_list<T> init)
    : m_mem(std::make_shared<std::vector<T>>(init.begin(), init.end()))
    , m_data(m_mem->data())
    , m_size(m_mem->size())
    { }

    SharedMem(SharedMem& other) = default;        // best-effort for copy-construction
    SharedMem(SharedMem const& other) = delete;   // disallow, would circumvent const-correctness

    SharedMem& operator = (SharedMem const& other) {
        std::copy(other.m_data, other.m_data + other.m_size, m_data);
        return *this;
    }

    std::size_t size() const
    { return m_size; }
    T& operator [] (std::size_t index)
    { return m_data[index]; }
    T const& operator [] (std::size_t index) const
    { return m_data[index]; }

    SharedMem slice(std::size_t first, std::size_t last) {
        SharedMem<T> ret(*this);
        ret.m_data += first;
        ret.m_size = last - first;
        return ret;
    }
    SharedMem const slice(std::size_t first, std::size_t last) const {
        SharedMem<T> ret(*this);
        ret.m_data += first;
        ret.m_size = last - first;
        return ret;
    }

private:
    std::shared_ptr<std::vector<T>> m_mem;   // shared underlying memory
    T* m_data;                               // start of slice
    std::size_t m_size;                      // size of slice
};

预定用途:

代码语言:javascript
复制
int main(int argc, char** argv) {
    SharedMem<int> a { 0, 1, 2, 3, 4 };
    SharedMem<int> b { 8, 9 };
    SharedMem<int> c = a;   // shallow copy of a, data is shared
    a.slice(1, 3) = b;      // a = [0, 8, 9, 3, 4]
    c[4] = 6;               // a = [0, 8, 9, 3, 6]
}

有件事告诉我,我走错了轨道。我认为我的方法存在以下问题:

  • 它违反了3的规则,我特别不喜欢为了修正const-正确性而禁用默认的复制构造函数。否则,可以创建const对象的非const副本,而后者可以修改前者的元素。
  • 复制构造和分配实现非常不同的操作。这就是我如何让c = aa.slice(1, 3) = b做正确的事情(实际上是非常不同的事情)。

我不确定我是否遇到了麻烦。问题:

  • 这个设计可以吗,还是会在路上造成问题?如果是的话,哪一个?
  • 如果有严重的缺陷,如何修复/避免它?

谢谢你的暗示。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-26 02:21:21

您需要分离类型,才能以正确的方式正确地工作。由于非常类似的原因,对于所有标准库容器,iteratorconst_iterator都是不同的类型。

尽管如此,我认为这在很大程度上取决于您的用例/代码库和编码风格是否建议沿着这条路线前进(因为保护编码器不受用例中可能永远不是问题的东西的影响很大)。

如果您想尝试一下,有一种解决方案可能如下所示:

代码语言:javascript
复制
namespace detail
{
    template<class T, bool Const>
    struct SharedInternalsT;

    template<class T>
    struct SharedInternalsT<T, true>
    {
        const T * m_data;
        std::size_t m_size;
    };

    template<class T>
    struct SharedInternalsT<T, false>
    {
        T * m_data;
        std::size_t m_size;
    };

    template<class T>
    using SharedInternals = SharedInternals<T, false>;

    template<class T>
    using ConstSharedInternals = SharedInternals<T, true>;
}

template<class T, bool Const>
class SharedMemT
{
public:

    using Traits = SharedMemTraits<T, Const>;
    using Ptr = typename Traits::Ptr;

    //now we can safely copy in a const correct way.
    SharedMemT(const SharedMemT & _other) :
    m_mem(_other.m_mem),
    m_internals(_other.m_internals)
    {

    }

private:

    std::shared_ptr<std::vector<T>> m_mem;
    detail::SharedInternals<T, Const> m_internals;
};

template<class T>
using SharedMem = SharedMemT<T, false>;

template<class T>
using ConstSharedMem = SharedMemT<T, true>;

这将是迈向解决办法的第一步。您很可能需要引入更多的间接,以便能够从非const版本正确地构造ConstVersions (可能通过使用std::enable_if等启用/禁用某些模板化的副本构造函数)。正如我说过的,只有在构建某种符合标准库的代码时,我才会沿着这条路线走下去。如果你只是为你的游戏或类似的东西构建一个小的实用程序,就忽略const的正确性,不要浪费你的时间。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42462970

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档