deep_const_ptr复制构造函数

时间:2014-04-14 11:07:17

标签: c++ pointers const smart-pointers

template <class T>
class deep_const_ptr
{
    T * priv;
public:
    deep_const_ptr(const deep_const_ptr & p_other); // copy ctor

    T const * operator->() const;
    T * operator->();
    ..... // other crap
};

void Cheese::doThings(const deep_const_ptr<Cheese> p_other)
{
    deep_const_ptr<Cheese> awayGoesTheConst(p_other); // I don't want this to work.
    awayGoesTheConst->doTerribleThings();
}

我想阻止复制构造从const到非const。

也许这甚至没有任何意义?

新的C ++ 11/14/17可以实现这一点吗?

编辑:

是的,问题是,如果我不给复制构造函数,STL容器就不会工作。而且我非常需要他们工作。

编辑:

deep_const_ptr是我在遇到STL容器和const对象问题时想出的解决方案。

class Shape
{
    private:
        std::list<Vertex *> m_vertices;
    public:
        virtual void std::list<Vertex*> * const getVertices() { return &m_vertices; }
        virtual void std::list<Vertex const *> * const getVertices() const { return &m_vertices; } // doesn't work, cannot convert between different types of lists
}

我想从不可变形状提供不可变顶点对象。

我提出的两个解决方案是自定义deep_const_ptr指针类型和自定义列表

Vertex const *& operator[](unsigned int) const;

2 个答案:

答案 0 :(得分:1)

我假设你所追求的是一个深度const指针实现以及如何处理它的复制。正如您已经发现的那样,一个简单的复制构造函数不会这样做,因为您将丢失指针上的const。没有其他方法可以禁止外部对象上的const删除,因此您只需要禁用复制构造函数。 现在你的问题的当前版本并不清楚为什么这是一个问题。从您的评论和上一个问题,我只能推断出你想在容器中使用指针,std :: vector&lt;&gt;特别。实现这项工作的关键是禁用复制,但启用移动(请注意,您需要rvalue-reference支持,这是C ++ 11的一部分):

template <class T>
class deep_const_ptr
{
    T * priv;
public:
    deep_const_ptr(const deep_const_ptr &)  = delete; // Do not allow this!
    deep_const_ptr& operator=(const deep_const_ptr &) = delete; // Nor this!

    deep_const_ptr(deep_const_ptr &&) = default; // But this is okay
    deep_const_ptr& operator=(deep_const_ptr &&) = default; // So is this!

    T const * operator->() const;
    T * operator->();
    ..... // other crap
};

容器通常只需移动而不是复制即可工作。

如果您确实需要对副本的支持,则需要将其用于仅支持const访问的其他类型。例如,您可以为deep_const_ptr专门设置const T,并且只在其中实现operator->operator*的常量变量。此外,您允许通过转换运算符将deep_const_ptr“降级”为deep_const_ptr。但这意味着某种多个所有者处理,例如引用计数,所以我将把它遗漏掉。 const和非const版本的行为也不同,这也很奇怪,但这是你的决定。就个人而言,我建议坚持这一举动。

答案 1 :(得分:0)

修改编辑:您再次更新了答案,让我回复一下。

只需使用const指针:

void Cheese::doThings(const Cheese* p_other)
{
    Cheese* p = p_other; // compiler ERROR
    p->doTerribleThings(); // can not do terrible things
}

或者如果你想要shared_ptr

void Cheese::doThings(const std::shared_ptr<const Cheese>& p_other)
{
    std::shared_ptr<Cheese> p = p_other; // compiler ERROR
    p->doTerribleThings(); // can not do terrible things
}

const ptr<T>ptr<const T>不同。第一个表示无法更改的指针对象,而指向的对象可以。第二个表示可以更改的指针对象,但指向的对象不能。

对于函数签名void foo(const A a)没有多大意义。你说&#34;给我一份副本,我保证不会改变它&#34;。谁在乎您对副本的处理方式?使用void foo(const A& a)以避免创建副本。

修改

  

我想允许复制nonconst - &gt; nonconst,nonconst - &gt;常量,   const - &gt;常量。

已经为#&#34;正常&#34;指针T*std::shared_ptr

<强>旧

只需使用T* operator->() const;即可。如果存储的指针是非常量指针,如Cheese*,它可以自动转换为const Cheese*

函数operator->()被标记为const,因为它不会更改指针对象本身。这与存储的对象无关!

vector的示例:

std::vector<Cheese*> a(10);
a[0] = 0; // does change a
Cheese* p = a[0]; // does not change a
a[0]->foo(); // still does not change a!

如果您希望deep_const_ptr指向的对象为const,则必须使用deep_const_ptr<const Cheese>

vector的示例:

std::vector<const Cheese*> a(10); // const pointer!
a[0] = 0; // does change a 
const Cheese* p = a[0]; // does not change a
a[0]->foo(); // now this only works if Cheese::foo is const