为遗留的c链表接口提供c++迭代器
Providing c++ iterators for a legacy C linked-list interface
我有一个Visual studio 2008 c++应用程序,我试图将迭代器支持添加到遗留的C- api的链表结构中。C语言的接口是这样的:
typedef struct _LINKED_LIST_INFO {
struct _LINKED_LIST_INFO* Next;
const char* name;
// more elements. some are fixed-size; others are pointers to other structures.
} LINKED_LIST_INFO;
DWORD GetLinkedList( LINKED_LIST_INFO* pInfo, PULONG pOutBufLen );
我希望能够这样使用它:
int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
MyLinkedList elements;
for( MyLinkedList::const_iterator it = elements.begin();
it != elements.end();
++it )
{
printf( "Name: %srn", it->Name().c_str() );
}
return 0;
}
我创建了这3个类。但是,我的MyInfoIterator
班有operator->()
的问题。我不能返回MyInfo
的临时指针,所以我得到错误:error C2440: 'return' : cannot convert from 'MyInfo' to 'const MyInfo *'
/// wrap the legacy C structure and provide C++ accessors
class MyInfo
{
public:
MyInfo( const LINKED_LIST_INFO& info ) : elem_( info ) { };
std::string Name() const { return elem_.name; };
private:
/// one element of the linked list
const LINKED_LIST_INFO& elem_;
}; // class MyInfo
namespace detail {
/// buffer to hold the legacy C linked-list
typedef std::vector< BYTE > MyBuffer;
/// iterator support for the legacy C linked-list
class MyInfoIterator
: public std::iterator< std::input_iterator_tag, MyInfo >
{
public:
explicit MyInfoIterator( MyBuffer& list ) : data_( list )
{
elem_ = reinterpret_cast< LINKED_LIST_INFO* >( &data_.front() );
};
MyInfoIterator() : elem_( NULL ) { };
MyInfoIterator& operator++()
{
elem_ = elem_->Next;
return *this;
};
value_type operator*() { return *elem_; };
// error C2440: 'return' : cannot convert from 'MyInfo' to 'const MyInfo *'
const value_type* operator->() { return elem_; };
friend bool operator==( const MyInfoIterator& i,
const MyInfoIterator& j )
{
return i.elem_ == j.elem_;
};
private:
/// linked-list of elements
MyBuffer data_;
/// current position within the element list
LINKED_LIST_INFO* elem_;
}; // class MyInfoIterator
bool operator!=( const MyInfoIterator& i, const MyInfoIterator& j )
{
return !operator==( i, j );
}
}; // namespace detail
/// provide iterator access for the legacy C linked-list API
class MyLinkedList
{
public:
typedef detail::MyInfoIterator const_iterator;
const_iterator begin() const
{
ULONG size = sizeof( LINKED_LIST_INFO );
detail::MyBuffer buffer( size );
DWORD ec = ::GetLinkedList(
reinterpret_cast< LINKED_LIST_INFO* >( &buffer.front() ), &size );
if( ERROR_BUFFER_OVERFLOW == ec )
{
buffer.resize( size );
ec = ::GetLinkedList(
reinterpret_cast< LINKED_LIST_INFO* >( &buffer.front() ), &size );
}
if( ERROR_SUCCESS != ec )
Win32Exception::Throw( ec );
return const_iterator( buffer );
};
const_iterator end() const { return const_iterator(); };
}; // class MyInfo
谢谢,PaulH
编辑:我不能改变旧的API或它的相关结构。
Edit2:
我认为我有一个工作的解决方案,保留我隐藏底层链表实现的意图,并通过返回static MyInfo
的地址来维护每个类的职责分离。
class MyInfo
{
// ...
protected:
MyInfo() : info_( NULL ) { };
void Set( const LINKED_LIST_INFO* info ) { info_ = info; };
private:
friend MyInfoIterator;
const LINKED_LIST_INFO* info_;
};
const value_type& MyInfoIterator::operator*() const
{
static MyInfo info;
info.Set( elem_ );
return info;
};
const value_type* MyInfoIterator::operator->() const
{
static MyInfo info;
info.Set( elem_ );
return &info;
};
保持简洁:
class MyInfoIterator
: public std::iterator< std::input_iterator_tag, _LINKED_LIST_INFO >
{
_LINKED_LIST_INFO* p;
public;
MyInfoIterator(_LINKED_LIST_INFO* pointer) : p(pointer) {}
[Same as you did]
value_type& operator*() { return *p; }
}
我相信你的value_type
是错误的…如果继承STL迭代器作为接口,则值类型需要是包含的类型。在您的例子中,您说您包含MyInfo
的元素,但您试图返回LINKED_LIST_INFO*
返回MyInfo
或者声明你的迭代器容器的value_type
为LINKED_LIST_INFO
可能需要第一个选项,因为您可能需要访问方法的帮助类,以便能够正确地操作结构体的成员。
编辑:很自然地,你应该意识到,只要有一个std::vector<LINKED_LIST_INFO>
或std::vector<MyInfo>
就可以提供你所需要的所有功能,而没有实现和维护问题。
实际上你不能有std::vector<MyInfo>
因为它不是默认的可构造函数所以一旦你解决了当前的错误你会得到另一个基于typedef std::vector< MyInfo > MyBuffer;
的错误除非你为MyInfo
提供默认构造函数否则在模板构建中将无法解决
您的value_type operator*() { return *elem_; }
格式相当不正确。在此二进制操作之后,不应该返回内部对象的副本。你应该返回一个引用。在您的情况下,您将此视为一个推导而不是一个乘法操作,这是可以的,但按值复制返回仍然是错误的。
这太可怕了(你不应该这样做):
class MyInfo {
char* name() const {
return ((_LINKED_LIST_INFO*)this)->name;
}
};
class MyInfoIterator
: public std::iterator< std::input_iterator_tag, MyInfo>
{
_LINKED_LIST_INFO* p;
public:
MyInfoIterator(LINKED_LIST_INFO* pointer) : p(pointer) {}
[Same as you did]
reference operator*() const { return *(MyInfo*)p; }
};
干净的方法可能是:
class MyInfo {
public:
[...]
private:
const LINKED_LIST_INFO* elem_;
}
class MyInfoIterator
: public std::iterator< std::input_iterator_tag, MyInfo>
{
mutable MyInfo p;
public:
MyInfoIterator(LINKED_LIST_INFO* pointer) : p(pointer) {}
[...]
reference& operator*() const { return p; }
pointer_type operator->() const { return &p; }
};
这是一些Boost迭代器的实现方式(我指的是干净的方式,不是第一个),例如参见[1]。
[1] http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/counting_iterator.html
看起来只要返回elem_
的地址就可以了。
const value_type* operator->() { return &elem_; };
您确定将您的遗留列表更改为适当的std::list
或std::vector
不会减少工作量吗?
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 如何在c++迭代器类型中包装std::chrono
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 对于set上的循环-获取next元素迭代器
- 为什么output_editor Concept不需要output_e迭代器标记
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 使用迭代器时如何访问对象在向量中的位置?
- std::vector::迭代器是否可以合法地作为指针
- 跟随整数索引列表的自定义类迭代器
- 不明白迭代器,引用和指针失效,一个例子
- 我可以使用反向迭代器作为ForwardIt吗
- ESP8266单片机矢量迭代器的C++问题
- 如何在C++中将迭代器作为函数参数传递
- 是否应避免从非常量迭代器转换为常量迭代器?
- 如何在 c++ 中将字符串迭代器变量传递给函数?
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- 为什么 C++ std::unordered_map 从 emplace/ 找到返回一个迭代器?