const和rvalue引用

时间:2014-04-07 22:21:35

标签: c++ c++11

我试图编写一个有效的列表和节点类,它们具有最少的代码来迭代它们。但是我很难完成所有标准。我希望这个代码在多线程环境中安全使用,所以如果可能的话,我希望迭代的所有函数和参数都是const,以确保没有写入状态,即它只是全部只读。所以我写了下面的类和迭代代码:

template<typename _Type_>
class Node
{
    template<typename _Type_> friend class List;

public:
    Node() : m_Next(NULL) {}
    Node(const _Type_& value) : m_Value(value), m_Next(nullptr()) {}

    const _Type_& Get() const { return m_Value; }
    Node&& Next() const { return std::move(*m_Next); }

    operator _Type_ () const { return m_Value; }

    _Type_& operator->() { return m_Value; }
    const _Type_& operator->() const { return m_Value; }

    operator bool() const { return m_Next != nullptr(); }

private:
    _Type_  m_Value;
    Node*   m_Next;
};

template<typename _Type_>
class List
{
public:

    typedef Node<_Type_> Node;

    List() : m_Head(NULL) {}

    void AddHead( const _Type_& value )
    {
        Node* pNode = GE_NEW(Node, value); 

        pNode->m_Next = &m_Head;
        m_Head = *pNode; 
    }

    Node&& Head() const { return std::move(m_Head); }

private:
    Node m_Head;
};

以及所有重要的迭代代码:

RenderTargetList::Node&& renderTarget = m_Targets.Head();
while( renderTarget )
{
    if(renderTarget->Format() == format)
    {
        return renderTarget.Get();
    }

    renderTarget = renderTarget.Next();
}

但是这不能编译为:

Node&& Head() const { return std::move(m_Head); }

在const函数函数中返回非const rvalue引用,即它必须是:

const Node&& Head() const { return std::move(m_Head); }

相反,但是这不起作用,因为迭代代码在赋值时失败:

renderTarget = renderTarget.Next();

因为renderTarget现在必须定义为:

const RenderTargetList::Node&& renderTarget = m_Targets.Head();

因为head返回一个const。基本上我似乎是一个混乱的const,引用,左值和右值。有人请帮忙!

由于

2 个答案:

答案 0 :(得分:3)

这是列表类的基本版本。请注意,迭代器类型和节点类型是两种不同的类型。这样,节点类型可以拥有该值,迭代器类型可以具有指针语义。

我会将其发布为社区维基,因为它更像是评论,而不是直接回答问题。

template<typename Type>
class List
{
private:
    // note that for immutable nodes, we could store `Type const`
    // and for an immutable list, `Node const* const`
    struct Node
    {
        Type  m_Value;
        Node* m_pNext;
    };

    Node* m_pHead;

public:

    class const_iterator
    {
    private:
        Node const* m_pNode;
        friend List;
        const_iterator(Node* p_pNode) : m_pNode(p_pNode) {}

    public:
        const_iterator() : m_pNode(nullptr) {}

        explicit operator bool() const
        { return m_pNode; }

        const_iterator Next() const
        { return {m_pNode->m_pNext}; }

        Type const& Get() const
        { return m_pNode->m_Value; }

        friend bool operator!=(const_iterator const& lhs,
                               const_iterator const& rhs)
        {
            return lhs.m_pNode != rhs.m_pNode;
        }
    };

    List() : m_pHead(nullptr) {}
    ~List()
    {
        // delete nodes
    }
    List(List const&) = delete; // needs to be customized
    List& operator=(List const&) = delete; // this one, too

    // the only function that modifies the list:
    void AddHead( Type const& value )
    {
        Node* pNode = new Node{value, m_pHead};
        m_pHead = pNode;
    }

    const_iterator Head() const
    { return {m_pHead}; }
};

用法示例:

#include <iostream>
int main()
{
    List<int> l;
    for(int i = 0; i < 10; ++i) l.AddHead(i); 

    auto it = l.Head();
    while(it)
    {
        std::cout << it.Get() << ", ";
        it = it.Next();
    }
}

答案 1 :(得分:0)

如果您的目标是线程安全,我认为您对const的观点感到困惑 - const不会为您提供线程安全的代码,只有体贴且易于理解的访问模式才能为您提供线程安全的代码。

我丢失了代码,这是没有使用const的线程sfae,如果你想保留&#34; AddHead&#34;你也需要这样做。当前形式的方法当然不是线程安全的。

如果您的代码是线程化的,则需要在代码中添加互斥锁,您可以在代码中访问可能被修改的代码或读取的另一个线程 - 关键区域 - 来自您的代码这些关键区域的结构可能非常短暂,因此没有多大的惩罚。