[英]Providing c++ iterators for a legacy C linked-list interface
我有一個Visual Studo 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: %s\r\n", 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>
為您提供所需的所有功能,而沒有實現和維護問題。
編輯#2:
實際上,您沒有std::vector<MyInfo>
因為它不是默認可構造的,因此一旦解決了當前錯誤,您將獲得另一個基於typedef std::vector< MyInfo > MyBuffer;
在為MyInfo
提供默認構造函數之前,它將無法在模板構造中解決
編輯#3:
您的value_type operator*() { return *elem_; }
value_type operator*() { return *elem_; }
的格式不正確。 在執行此二進制操作后,您不應返回內部對象的副本。 您應該返回參考。 在您的情況下,您將其視為deref而不是乘法運算,這很好,但是按值復制返回仍然是錯誤的。
看起來只需返回elem_
的地址elem_
。
const value_type* operator->() { return &elem_; };
您確定將舊列表適當地更改為std::list
或std::vector
工作不會少嗎?
這太可怕了(您不應該這樣做):
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.