我试图编写一个有效的列表和节点类,它们具有最少的代码来迭代它们。但是我很难完成所有标准。我希望这个代码在多线程环境中安全使用,所以如果可能的话,我希望迭代的所有函数和参数都是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,引用,左值和右值。有人请帮忙!
由于
答案 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;你也需要这样做。当前形式的方法当然不是线程安全的。
如果您的代码是线程化的,则需要在代码中添加互斥锁,您可以在代码中访问可能被修改的代码或读取的另一个线程 - 关键区域 - 来自您的代码这些关键区域的结构可能非常短暂,因此没有多大的惩罚。