[英]Providing c++ iterators for a legacy C linked-list interface
I have a Visual Studo 2008 C++ application where I am trying to add iterator support to a legacy C-API's linked-list structure. 我有一个Visual Studo 2008 C ++应用程序,试图在其中将迭代器支持添加到旧版C-API的链表结构中。 The C interface looks like this:
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 );
I would like to be able to use it like this: 我希望能够像这样使用它:
int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
MyLinkedList elements;
for( MyLinkedList::const_iterator it = elements.begin();
it != elements.end();
++it )
{
printf( "Name: %s\r\n", it->Name().c_str() );
}
return 0;
}
So, I've created these 3 classes. 因此,我创建了这3个类。 But, my
MyInfoIterator
class has a problem with the operator->()
. 但是,我的
MyInfoIterator
类的operator->()
有问题。 I can't return a temporary pointer to MyInfo
, so I get the error: error C2440: 'return' : cannot convert from 'MyInfo' to 'const MyInfo *'
我无法返回指向
MyInfo
的临时指针,所以出现错误: error C2440: 'return' : cannot convert from 'MyInfo' to 'const MyInfo *'
What is a good solution to this problem? 对这个问题有什么好的解决方案?
/// 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
Thanks, PaulH 谢谢PaulH
Edit: 编辑:
I cannot change the legacy API or it's associated structure. 我无法更改旧版API或它的关联结构。
Edit2: EDIT2:
I think I have a working solution that preserves my intent of hiding the underlying linked-list implementation and maintains the separation of responsibilities for each class by returning the address of a static MyInfo
. 我认为我有一个可行的解决方案,可以保留隐藏底层链接列表实现的意图,并通过返回
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;
};
Keep it simple : 把事情简单化 :
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; }
}
I believe your value_type
is wrong ... if you inherit STL iterator as an interface the value type needs to be of the type you contain. 我相信您的
value_type
是错误的...如果您将STL迭代器作为接口继承,则值类型必须为您所包含的类型。 In your case you say that you contain elements of MyInfo
but you are attempting to return a LINKED_LIST_INFO*
在您的情况下,您说您包含
MyInfo
元素,但是您尝试返回LINKED_LIST_INFO*
Either return a MyInfo
or declare your iterator container to have a value_type
of LINKED_LIST_INFO
. 返回
MyInfo
或声明您的迭代器容器的value_type
为LINKED_LIST_INFO
。
Probably want the first option as you may need the helper class for accessor methods to be able to properly manipulate the members of the struct. 可能需要第一个选项,因为您可能需要辅助类来使访问器方法能够正确地操纵结构的成员。
Edit: 编辑:
Naturally you should realize that simply having a std::vector<LINKED_LIST_INFO>
or std::vector<MyInfo>
gives you all the functionality you need with none of the implementation and maintenance issues. 自然地,您应该认识到,仅拥有
std::vector<LINKED_LIST_INFO>
或std::vector<MyInfo>
为您提供所需的所有功能,而没有实现和维护问题。
Edit #2: 编辑#2:
Actually you can't have a std::vector<MyInfo>
because it's not default constructible so once you resolve your current error you will get another one based on typedef std::vector< MyInfo > MyBuffer;
实际上,您没有
std::vector<MyInfo>
因为它不是默认可构造的,因此一旦解决了当前错误,您将获得另一个基于typedef std::vector< MyInfo > MyBuffer;
which will fail to resolve in template construction until you provide a default constructor for MyInfo
在为
MyInfo
提供默认构造函数之前,它将无法在模板构造中解决
Edit #3: 编辑#3:
Your value_type operator*() { return *elem_; }
您的
value_type operator*() { return *elem_; }
value_type operator*() { return *elem_; }
is rather improperly formed. value_type operator*() { return *elem_; }
的格式不正确。 You should not return a copy of the internal object after this binary operation. 在执行此二进制操作后,您不应返回内部对象的副本。 You should return a reference.
您应该返回参考。 In your case you're treating this as a deref rather than a multiplication operation which is fine but a copy-by-value return is still wrong.
在您的情况下,您将其视为deref而不是乘法运算,这很好,但是按值复制返回仍然是错误的。
It looks like just returning the address of elem_
should do it. 看起来只需返回
elem_
的地址elem_
。
const value_type* operator->() { return &elem_; };
Are you sure it wouldn't be less work to change your legacy list to a std::list
or std::vector
as appropriate though? 您确定将旧列表适当地更改为
std::list
或std::vector
工作不会少吗?
This is horrible (you should not do this) : 这太可怕了(您不应该这样做):
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; }
};
The clean way is probably : 干净的方法可能是:
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; }
};
This is how some Boost iterator are implemented (I mean the clean way, not the first one), see [1] for example. 这就是一些Boost迭代器的实现方式(我的意思是干净的方法,而不是第一种),例如,请参见[1]。
[1] http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/counting_iterator.html [1] http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/counting_iterator.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.